How to use multi-threaded wait and notify protocols
Specifically, someone can tell me what's wrong with this code It should start the thread, so it should print "input thread..." five times and wait until notifyall() is called However, it randomly prints "enter..." and "finish..." and is still waiting for others
public class ThreadTest implements Runnable { private int num; private static Object obj = new Object(); ThreadTest(int n) { num=n; } @Override public void run() { synchronized (obj) { try { System.out.println("Entering thread "+num); obj.wait(); System.out.println("Done Thread "+num); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { Runnable tc; Thread t; for(int i=0;i<5;i++) { tc = new ThreadTest(i); t = new Thread(tc); t.start(); } synchronized (obj) { obj.notifyAll(); } } }
Solution
You didn't make any obvious errors on the method call, but you have a race condition
Although in an ideal world, the main thread will reach its synchronized block after all worker threads arrive at the wait () call, there is no guarantee (you explicitly tell the virtual machine that you don't want the threads to execute in order and make threads with the main thread) It may happen (for example, if you have only one core) that the thread scheduler decides to block all worker threads immediately and they begin to allow the main thread to continue The worker thread may be switched out of context due to a cache miss It may be that a worker thread blocks I / O (print statement) and the main thread switches in its position
Therefore, if the main thread tries to reach the synchronization block before all worker threads reach the wait () call, those worker threads that have not yet reached the wait () call will not run as expected Because the current settings do not allow you to control this operation, you must add explicit processing for this You can add a variable that will be added when each worker thread reaches wait() and the main thread does not call notifyall() until this variable reaches 5, or you can use the main thread loop and call notifyall() repeatedly So that worker threads can be published in multiple groups
Take a look at Java util. Concurrent package - there are several lock classes that provide more powerful functions than basic synchronous locks - as always, Java can save you from reinventing the wheel Countdown latch seems particularly relevant
In short, concurrency is difficult You must design to ensure that when the thread executes in an order you don't want, everything is still valid and the order you want