There are 2 problems in your code:
First you are synchronizing/waiting on the monitor "this", which is the actual object, so in case of T1 it is T1 and for T2 it's T2. To do this properly both threads need to synchronize/wait on the same object. A common way to do this is to specifically create such an object like this:
final static Object monitor = new Object();
Please note that the final
keyword is important here, you do not want to accidentally change the monitor in between.
But even if you do this, there is no guarantee that during the time T2 is calling notifyAll()
that T1 is already waiting, as the order of execution with threads is undefined. Effectively that can cause T1 to deadlock during the last wait-call after remove, as T2 is already done.
Edit: How to do this with a Phaser
Declare a Phaser instance that both threads can use:
static final Phaser phaser = new Phaser(2); // 2 threads = 2 parties
The run method of T1 becomes:
while (!list.isEmpty()) {
System.out.println(list.remove(0));
phaser.arriveAndAwaitAdvance();
phaser.arriveAndAwaitAdvance();
}
phaser.arriveAndDeregister();
And the run method of T2 becomes:
while (!list.isEmpty()) {
phaser.arriveAndAwaitAdvance();
System.out.println(list.remove(0));
phaser.arriveAndAwaitAdvance();
}
phaser.arriveAndDeregister();
The deregister is not necessary in this case, but acts as a safety mechanism: once deregistered the system can continue without the thread that just finished.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…