Multi-Threading problem

S

skoobie

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
 
B

blmblm

Why would 'threadS' not be null?

[ snip ]
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 ]

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

blmblm

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

blmblm

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. :)?
 
A

Arne Vajhøj

Lew said:
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
 
R

Roedy Green

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
 
K

Knute Johnson

skoobie said:
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);
}
});
}
}
 
J

JK

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
 
B

blmblm

(e-mail address removed) 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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top