Multi-Threading problem

Discussion in 'Java' started by skoobie, Jun 17, 2008.

  1. skoobie

    skoobie Guest

    Hi, this is my first post so please excuse any mistakes. I basically
    have scoured over the net and have read many books on Multi-threading
    and I am struggling to use it for this problem.

    The problem is creating a digitalclock (displaying hours, minutes and
    seconds) program which uses a different thread for hours, minutes and
    seconds.

    Using one thread would not be a problem ( I can do that fine) but
    synchronising 3 threads with split second timing is proving to be
    difficult. So far I can get the seconds to work but am struggling to
    incorporate the minutes and hours.

    What I have set out to do is to make hours and mins threads start
    first and then wait();
    The seconds thread sleeps every one second and set new seconds each
    time.
    if seconds == 0, notify the minutes thread
    The minutes thread then updates minutes and should notify hours when
    it reaches 0.

    I have written good code for setting the seconds and displaying it. I
    am just having problems synchronising the 3 threads. Here is a snipet
    of my code:

    public void start() {
    if (threadS == null) {
    threadS = new Thread(new Clock("seconds")); //this, the current
    object instance
    threadS.setPriority(10); // ensures second starts first
    threadS.start();
    }
    if (threadM == null) {
    threadM = new Thread(new Clock("minutes")); //this, the current
    object instance
    threadM.setPriority(5); // ensures second starts first
    // threadM.start();
    }

    if (threadH == null) {
    threadH = new Thread(new Clock("hours")); //this, the current
    object instance
    threadH.setPriority(2); // ensures second starts first
    threadH.start();
    }

    if (startMins == true) { // flag to start thread
    System.err.println("Hello");
    threadM.start();
    }

    /* and in the action part of the code Synchronised method belonging to
    run(); */

    while (threadS == Thread.currentThread()) {
    // setting new seconds code

    try {
    Thread.sleep(addMilliSec);
    } catch (InterruptedException e) { }

    if (newSeconds == 00)) {
    startMins = true;
    start(); // without this threadM doesn't start!
    notify();
    }

    System.out.println(getDigitalClock());
    }

    while (threadM == Thread.currentThread()) {

    minute = newMinutes();
    try {
    wait();
    } catch (InterruptedException e) {}
    }
    // and so fourth..

    The minute increments correctly first time but then I get an
    IllegalThreadStateException.
    I know why this is.. its because I am trying to start a thread that's
    already started before. But if I don't put start() in there.. seconds
    continue to update but minutes and seconds don't.

    What am I missing?

    Any guidance to this would be very helpful. his is very frustrating
    because I've got working solutions with one thread but have hit a dead
    end trying to use 3.

    Thanks for reading,

    Skoobie
    skoobie, Jun 17, 2008
    #1
    1. Advertising

  2. skoobie

    Guest

    In article <>,
    Lew <> wrote:
    > skoobie wrote:
    > > public void start() {
    > > if (threadS == null) {

    >
    > Why would 'threadS' not be null?
    >
    > > threadS = new Thread(new Clock("seconds")); //this, the current
    > > object instance


    [ snip ]

    > > threadS.setPriority(10); // ensures second starts first

    >
    > It ensures no such thing.


    Indeed. The conventional wisdom (as I understand it) is that
    attempting to get proper synchronization by setting thread
    priorities is a Bad Idea.

    [ snip ]

    > > Any guidance to this would be very helpful. his is very frustrating
    > > because I've got working solutions with one thread but have hit a dead
    > > end trying to use 3.


    It might help people suggest solutions if we knew whether the OP's
    objective is to learn more about multithreading and synchronization
    or to solve some real problem.

    > Create a class, possibly an inner class, with a 'run()' method that implements
    > Runnable for each of your threads. Have the 'run()' for one do the hours,
    > another the minutes, the third the seconds.


    Advice seconded, more or less.

    > Have them update the state of the
    > members of the instance via synchronized setters. Now you never have to check
    > if the current thread is the one running - each thread only has one
    > responsibility so it knows if it's aware, it's running. The updater threads
    > can start timers to trigger updates once per hour, minute and second,
    > respectively.


    You could do that .... but if the objective is to learn about wait()
    and notify(), it seems like it might be more interesting to just have
    the seconds-updating thread repeatedly sleep 1 second, and manage
    everything else with appropriate use of wait() and notifyAll().

    Synchronized getters and setters are not a bad idea in general,
    but I wonder whether they might not be overkill here -- for int
    variables, marking them "volatile" should be enough to be sure
    they actually get updated in memory (rather than being kept in a
    register), and with ints there's no risk of simultaneous updates
    somehow corrupting internal state, right? (Maybe that's what you
    meant below.)

    And for this problem you need larger atomic operations anyway,
    for example "add one to seconds, and if the result is 60 do
    something", no?

    > Have another thread handle update of the display, using synchronized getters
    > to obtain the values for display.
    >
    > You could use volatile member values as a way to synchronize.


    I put together a semi-hacked-up solution using wait and notifyAll,
    which I can post if there's interest. My advice to the OP would
    be -- assuming the objective is to learn -- to aim for a solution
    where each thread uses, at appropriate times, the standard
    mechanism for waiting for a condition to become true:

    while (!condition) wait();

    and the standard (AIUI) corresponding mechanism for waking up
    waiting threads:

    condition = true; notifyAll();

    It's kind of a fun problem to solve just with wait and notify, IMO.

    --
    B. L. Massingill
    ObDisclaimer: I don't speak for my employers; they return the favor.
    , Jun 19, 2008
    #2
    1. Advertising

  3. skoobie

    Guest

    In article <>,
    Lew <> wrote:
    > wrote:
    > > Synchronized getters and setters are not a bad idea in general,
    > > but I wonder whether they might not be overkill here -- for int
    > > variables, marking them "volatile" should be enough to be sure
    > > they actually get updated in memory (rather than being kept in a
    > > register), and with ints there's no risk of simultaneous updates
    > > somehow corrupting internal state, right?

    >
    > Lew wrote:
    > >> You could use volatile member values as a way to synchronize.

    >
    > wrote:
    > > (Maybe that's what you meant below.)

    >
    > Ya think?


    Every once in a while, yes. Sometimes I even do so (think) before
    posting to Usenet. (Did you mean for your reply to be as snarky as
    it's coming across to me?)

    > I said synchronized getters and setters, but I didn't explicitly state one had
    > to synchronize them with the 'synchronized' keyword, and I mentioned
    > 'volatile' specifically to highlight that alternative means of
    > synchronizing them.


    Yes, you did mention that, but I'd have said that a mention of
    "synchronized getters and setters" normally implies use of the
    keyword "synchronized", and that the form of synchronization
    provided by "volatile" is pretty weak .... Well. This is
    quibbling about terminology, and possibly not very important.

    Just out of curiosity, your suggestion to use timers -- what do
    you envision happening when all three fire more or less at the
    same time (as they would once per hour, right?). (And I don't
    mean *that* to be as snarky as it might sound.)

    I'll add here that I was surprised by Patricia's suggestion to
    use a BlockingQueue, but that makes sense too.

    --
    B. L. Massingill
    ObDisclaimer: I don't speak for my employers; they return the favor.
    , Jun 19, 2008
    #3
  4. skoobie

    Guest

    In article <>,
    Patricia Shanahan <> wrote:
    > wrote:
    > ...
    > > I'll add here that I was surprised by Patricia's suggestion to
    > > use a BlockingQueue, but that makes sense too.

    >
    > To me, it seems natural to prefer a message passing interface to shared
    > memory with synchronization, given the choice and assuming no
    > performance problem. I've spent a lot of time working with explicit
    > shared memory, including helping to design shared memory multiprocessor
    > systems, but I still find it takes me a lot of thinking to get it right.
    >
    > In this case, there would be a total of 61 messages per hour, hardly a
    > performance issue. I would not roll my own queuing system to do this
    > problem that way, but given java.util.concurrent, why not use it?
    >


    So why did I find it surprising, given that I've probably written a
    lot more message-passing code than multithreaded-with-shared-memory
    code .... I don't know! and your explanation above generates
    another "oh! I didn't think of it that way! but okay ...."
    moment, this time about thinking in terms of message passing.
    Interesting!

    I'm still kind of inclined to think that what to recommend to the OP
    depends on the goal (learning versus just-need-to-make-this-work),
    but if you want to argue that learning about library classes is at
    least as important as learning to roll one's own, I won't argue.
    Much, maybe. :)?

    --
    B. L. Massingill
    ObDisclaimer: I don't speak for my employers; they return the favor.
    , Jun 19, 2008
    #4
  5. Lew wrote:
    > skoobie wrote:
    >> public void start() {
    >> threadS = new Thread(new Clock("seconds")); //this, the
    >> current
    >> object instance

    >
    > What's with the wide, wide, wide, wide world of TAB indentation?
    >
    > Two spaces is sufficient indentation for Usenet. What you have is
    > harder to read.


    Or 4 spaces to follow common practice ...

    Arne
    Arne Vajhøj, Jun 20, 2008
    #5
  6. skoobie

    Roedy Green Guest

    On Tue, 17 Jun 2008 15:44:37 -0700 (PDT), skoobie
    <> wrote, quoted or indirectly quoted someone
    who said :

    >Using one thread would not be a problem ( I can do that fine) but
    >synchronising 3 threads with split second timing is proving to be
    >difficult. So far I can get the seconds to work but am struggling to
    >incorporate the minutes and hours.


    That is making it too complicated. All you need is a timer that goes
    off sporadically, say every 1/10 second -- nothing accurate needed.
    When it wakes up, it gets the precise time, converts it to a String
    and pokes it into a Component. There is no need to try to make it go
    off exactly every second. That sort of thing will get you in trouble
    since any sleeping is only approximate and depends on how busy the
    machine is.

    See how SetClock entertains you with both running your inaccurate PC
    time atomic corrected time.

    I did it with an explicit Thread. I could have done it more easily
    with a Swing Timer, but that did not exist at the time I wrote the
    code.

    See http://mindprod.com/webstart/setclock.html

    http://mindprod.com/jgloss/timer.html
    --

    Roedy Green Canadian Mind Products
    The Java Glossary
    http://mindprod.com
    Roedy Green, Jun 20, 2008
    #6
  7. skoobie wrote:
    > Hi, this is my first post so please excuse any mistakes. I basically
    > have scoured over the net and have read many books on Multi-threading
    > and I am struggling to use it for this problem.
    >
    > The problem is creating a digitalclock (displaying hours, minutes and
    > seconds) program which uses a different thread for hours, minutes and
    > seconds.
    >
    > Using one thread would not be a problem ( I can do that fine) but
    > synchronising 3 threads with split second timing is proving to be
    > difficult. So far I can get the seconds to work but am struggling to
    > incorporate the minutes and hours.
    >
    > What I have set out to do is to make hours and mins threads start
    > first and then wait();
    > The seconds thread sleeps every one second and set new seconds each
    > time.
    > if seconds == 0, notify the minutes thread
    > The minutes thread then updates minutes and should notify hours when
    > it reaches 0.
    >
    > I have written good code for setting the seconds and displaying it. I
    > am just having problems synchronising the 3 threads. Here is a snipet
    > of my code:
    >
    > public void start() {
    > if (threadS == null) {
    > threadS = new Thread(new Clock("seconds")); //this, the current
    > object instance
    > threadS.setPriority(10); // ensures second starts first
    > threadS.start();
    > }
    > if (threadM == null) {
    > threadM = new Thread(new Clock("minutes")); //this, the current
    > object instance
    > threadM.setPriority(5); // ensures second starts first
    > // threadM.start();
    > }
    >
    > if (threadH == null) {
    > threadH = new Thread(new Clock("hours")); //this, the current
    > object instance
    > threadH.setPriority(2); // ensures second starts first
    > threadH.start();
    > }
    >
    > if (startMins == true) { // flag to start thread
    > System.err.println("Hello");
    > threadM.start();
    > }
    >
    > /* and in the action part of the code Synchronised method belonging to
    > run(); */
    >
    > while (threadS == Thread.currentThread()) {
    > // setting new seconds code
    >
    > try {
    > Thread.sleep(addMilliSec);
    > } catch (InterruptedException e) { }
    >
    > if (newSeconds == 00)) {
    > startMins = true;
    > start(); // without this threadM doesn't start!
    > notify();
    > }
    >
    > System.out.println(getDigitalClock());
    > }
    >
    > while (threadM == Thread.currentThread()) {
    >
    > minute = newMinutes();
    > try {
    > wait();
    > } catch (InterruptedException e) {}
    > }
    > // and so fourth..
    >
    > The minute increments correctly first time but then I get an
    > IllegalThreadStateException.
    > I know why this is.. its because I am trying to start a thread that's
    > already started before. But if I don't put start() in there.. seconds
    > continue to update but minutes and seconds don't.
    >
    > What am I missing?
    >
    > Any guidance to this would be very helpful. his is very frustrating
    > because I've got working solutions with one thread but have hit a dead
    > end trying to use 3.
    >
    > Thanks for reading,
    >
    > Skoobie


    Here's my entry for the "Strange Clock" contest. I used listeners to
    notify the minutes and hours to increment. I liked Patricia's idea of a
    blocking queue but that seemed too simple.

    You need to set this clock. Enter a value in the hours/minutes field
    and press <ENTER> to update the counter. The seconds field is reset to
    00 when <ENTER> is pressed.

    import java.awt.*;
    import java.awt.event.*;
    import java.util.*;
    import javax.swing.*;
    import javax.swing.event.*;

    public class StrangeClock extends JPanel {
    public StrangeClock() {
    final ClockField seconds = new ClockField(60);
    final ClockField minutes = new ClockField(60);
    final ClockField hours = new ClockField(24);

    new javax.swing.Timer(1000,new ActionListener() {
    public void actionPerformed(ActionEvent ae) {
    seconds.increment();
    }
    }).start();

    seconds.addRollOverEventListener(new RollOverEventListener() {
    public void rollOverEventOccurred(RollOverEvent roe) {
    minutes.increment();
    }
    });

    minutes.addRollOverEventListener(new RollOverEventListener() {
    public void rollOverEventOccurred(RollOverEvent roe) {
    hours.increment();
    }
    });

    seconds.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent ae) {
    seconds.clear();
    }
    });

    minutes.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent ae) {
    minutes.set();
    }
    });

    hours.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent ae) {
    hours.set();
    }
    });

    add(hours);
    add(new JLabel(":"));
    add(minutes);
    add(new JLabel(":"));
    add(seconds);
    }

    public class RollOverEvent extends EventObject {
    public RollOverEvent(Object source) {
    super(source);
    }
    }

    public interface RollOverEventListener extends EventListener {
    public void rollOverEventOccurred(RollOverEvent roe);
    }

    public class ClockField extends JTextField {
    private int count;
    private final int limit;
    protected EventListenerList eList = new EventListenerList();

    public ClockField(int limit) {
    super("00");
    this.limit = limit;
    }

    public void increment() {
    if (++count == limit) {
    fireRollOverEvent(new RollOverEvent(this));
    count = 0;
    }
    setText(String.format("%02d",count));
    }

    public void clear() {
    count = 0;
    setText(String.format("%02d",count));
    }

    public void set() {
    try {
    count = Integer.parseInt(getText());
    } catch (NumberFormatException nfe) {
    nfe.printStackTrace();
    }
    setText(String.format("%02d",count));
    }

    public void addRollOverEventListener(
    RollOverEventListener listener) {
    eList.add(RollOverEventListener.class,listener);
    }

    public void removeRollOverEventListener(
    RollOverEventListener listener) {
    eList.remove(RollOverEventListener.class,listener);
    }

    void fireRollOverEvent(RollOverEvent roe) {
    Object[] listeners = eList.getListenerList();
    for (int i=0; i<listeners.length; i+=2)
    if (listeners == RollOverEventListener.class)

    ((RollOverEventListener)listeners[i+1]).rollOverEventOccurred(roe);
    }
    }

    public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
    public void run() {
    JFrame f = new JFrame("Strange Clock");
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    StrangeClock sc = new StrangeClock();
    f.add(sc,BorderLayout.CENTER);
    f.pack();
    f.setVisible(true);
    }
    });
    }
    }

    --

    Knute Johnson
    email s/nospam/knute2008/

    --
    Posted via NewsDemon.com - Premium Uncensored Newsgroup Service
    ------->>>>>>http://www.NewsDemon.com<<<<<<------
    Unlimited Access, Anonymous Accounts, Uncensored Broadband Access
    Knute Johnson, Jun 20, 2008
    #7
  8. skoobie

    JK Guest

    skoobie wrote:

    [snip]

    The code you posted does not look like it was written by a person who
    has scoured the 'net and read multiple books about multithreading. It
    kinda looks like homework, in fact; apologies if I'm wrong about that.
    Anyway, I'll try to get you going.

    I assume you want to use three threads because you want to learn how to
    get multiple threads to interact, not because you think three threads
    are actually necessary to solve this problem. So let's just establish
    the data that we need, and start three threads, one for updating each
    time interval. These threads do nothing but sleep; the point is just to
    start them.

    public class MyClock {

    private int seconds=0;
    private int minutes=0;
    private int hours=0;

    private void secondsThread() {
    while (true) {
    try {Thread.sleep(1000);} catch (InterruptedException ex) {}
    System.out.println("The current time is: "+
    seconds+':'+minutes+':'+hours);
    }
    }

    private void minutesThread() {
    while (true) {
    try {Thread.sleep(1000);} catch (InterruptedException ex) {}
    System.out.println("Minute thread woke up.");
    }
    }

    private void hoursThread() {
    while (true) {
    try {Thread.sleep(1000);} catch (InterruptedException ex) {}
    System.out.println("Hour thread woke up.");
    }
    }

    public static void main(String[] args) {
    final MyClock myClock=new MyClock();

    // Start the seconds thread. We'll use the usual idiom of an
    // anonymous Runnable to execute a method on myClock in a
    // new thread. We don't care about the actual Thread instances;
    // all of them can just run forever.
    new Thread(new Runnable() {
    public void run() { myClock.secondsThread(); }
    }).start(); // Don't forget to start the thread!

    // Start the minutes thread.
    new Thread(new Runnable() {
    public void run() { myClock.minutesThread(); }
    }).start();

    // Start the hours thread. We'll just use the main()
    // thread for this.
    myClock.hoursThread();
    }

    }

    OK. Invoking MyClock.main() will now create a MyClock instance and call
    each of its secondsThread(), minutesThread(), and hoursThread() methods
    in different threads.

    So what do we want these threads to do? I'm not going to solve that
    problem for you right now. You will need to think carefully about the
    conditions under which you want each thread to wake up and update the
    seconds, minutes, and hours member variables. Here's a hint: it should
    not matter in what order the threads start; it should only matter that
    they wake up and do their appointed jobs when the appropriate conditions
    occur.

    Hope this helps.

    -- JK

    --
    (declare (antichrist i) (anarchist i)) ; -- the sexp-pistols
    JK, Jun 22, 2008
    #8
  9. skoobie

    Guest

    In article <>,
    Patricia Shanahan <> wrote:
    > wrote:
    > > In article <>,
    > > Patricia Shanahan <> wrote:
    > >> wrote:
    > >> ...
    > >>> I'll add here that I was surprised by Patricia's suggestion to
    > >>> use a BlockingQueue, but that makes sense too.
    > >> To me, it seems natural to prefer a message passing interface to shared
    > >> memory with synchronization [ .... ]


    > > So why did I find it surprising, given that I've probably written a
    > > lot more message-passing code than multithreaded-with-shared-memory
    > > code .... [ .... ]


    > I think this may be a consequence of Java's initial lack of built-in
    > support for thread communication approaches other than shared memory
    > with synchronization. We all got used to using that directly, rather
    > than treating it as a low level facility that should be used mainly to
    > build conventional structures such as message passing and semaphores.
    >
    > I've been trying to practice considering java.util.concurrent before
    > working with shared memory directly, but it's a difficult habit to change.


    Belatedly following up to say that you're probably exactly right
    about why my first inclination seems to involve using the low-level
    stuff, and that the implicit suggestion to make a conscious effort
    to use the new stuff is a good one!

    > Incidentally, the problem could also be solved using a pair of
    > semaphores. For example, the minutes thread would acquire from a
    > semaphore, and the seconds thread would release the semaphore each time
    > its counter wraps.


    Oh yeah, you could ....

    I thought about posting my semi-hacked-up solution for comments,
    but maybe not. But it was interesting to see how many different
    ways people came up with of approaching this problem.

    [ snip ]

    > I am sure this is a learning exercise of some sort, because the single
    > thread implementation is obviously simpler and at least as effective as
    > the multi-threaded one.
    >
    > The issue is whether the objective is to learn to use shared memory and
    > synchronization directly, or to learn to write multi-threaded code in
    > Java as it is now.


    Yeah ....

    I wonder whether at some point the OP will come back and tell
    us what the objective was, and whether any of the suggestions
    were helpful.

    --
    B. L. Massingill
    ObDisclaimer: I don't speak for my employers; they return the favor.
    , Jun 26, 2008
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Garry Hodgson
    Replies:
    5
    Views:
    713
  2. Replies:
    38
    Views:
    1,255
    Dennis Lee Bieber
    Feb 15, 2005
  3. Haitao
    Replies:
    2
    Views:
    357
    Arne Vajhøj
    Jan 13, 2008
  4. Pradip
    Replies:
    0
    Views:
    401
    Pradip
    Mar 31, 2008
  5. akineko
    Replies:
    3
    Views:
    2,597
    Jesse Noller
    Jan 29, 2009
Loading...

Share This Page