I am trying to print a statement in Java using threads, where each thread should print part of the statement. However, following code does not always output statement in correct order.
class NewThread implements Runnable {
String msg;
Thread t;
NewThread(String str) {
t = new Thread(this);
msg = str;
}
public void run() {
PrintMsg(msg);
}
synchronized void PrintMsg(String msg) {
System.out.println(msg);
try {
wait();
} catch (InterruptedException e) {
System.out.println("Exception");
}
System.out.println(msg);
notify();
}
}
class ThreadDemo {
public static void main(String args[]) {
NewThread t1, t2, t3;
t1 = new NewThread("Humphry Dumprey");
t2 = new NewThread("went to the hill");
t3 = new NewThread("to fetch a pail of water");
t1.t.start();
t2.t.start();
t3.t.start();
try {
t1.t.join();
t2.t.join();
t3.t.join();
} catch (InterruptedException e) {
System.out.println("Main Thread Interrupted");
}
}
}
I suspect problem with inter-thread communication.
解决方案
I think your problem is in this method:
synchronized void PrintMsg(String msg) {
System.out.println(msg);
try {
wait();
} catch (InterruptedException e) {
System.out.println("Exception");
}
System.out.println(msg);
notify();
}
The thread that call it are going to call wait() which causes them to wait indefinitely for someone to call notify(). But there are no other calls to notify() so they all will stop there.
Also, because the method is synchronized each thread is also waiting on it's own NewThread instance. I think you meant to have all threads waiting and notifying on the same object?
From comments:
want to wait a thread until it finishes writing a part of statement. It should be like this : Thread 1 prints "Humphry Dumprey" Thread 2 prints "went to the hill" Thread 3 prints "to fetch a pail of water" and these three threads should execute in sequence such that the statement gets printed in right sequence.
I never understand these sorts of questions. The whole point of threads are that the run asynchronously in parallel. If you want them to print 3 things in a row then 1 thread should be used instead.
If you need to do this for some assignment then there a couple different ways you can do it.
Each thread could synchronize on the same AtomicInteger. Thread #1 would do its print if the integer was 1, thread #2 when it is 2, .... You could pass in the order as a value field to the NewThread constructor. After they print they values they increment the integer and notifyAll().
static final AtomicInteger counter = new AtomicInteger(1);
...
synchronized (counter) {
// looping like this is always recommended
while (counter.get() != value) {
counter.wait();
}
System.out.println(...);
counter.incrementAndGet();
counter.notifyAll();
}
You could use 2 CountdownLatch so thread #2 calls countDown1.await(); and thread #3 waits for countDown2.await();. Then after thread #1 prints its message it calls countDown1.countDown() and after thread #2 prints its message it calls countDown2.countDown().