具体来说,有人可以告诉我这段代码有什么问题.它应该启动线程,所以应该打印“输入线程…”5次,然后等到调用notifyAll().但是,它会随机打印“输入……”和“完成……”,并且仍在等待其他人.
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();
}
}
}
解决方法
你没有对方法调用做任何明显的错误,但是你有一个
race condition.
虽然在一个理想的世界中,主线程将在所有工作线程到达wait()调用后到达其synchronized块,但无法保证(您明确告诉虚拟机您不希望线程按顺序执行用主线程制作线程).可能发生(例如,如果您只有一个核心)线程调度程序决定立即阻止所有工作线程,它们开始允许主线程继续.可能由于高速缓存未命中而将工作线程切换出上下文.可能是一个工作线程阻塞I / O(print语句)并且主线程在其位置切换.
因此,如果主线程在所有工作线程到达wait()调用之前设法到达同步块,则那些尚未到达wait()调用的工作线程将无法按预期运行.由于当前设置不允许您控制此操作,因此必须添加对此的显式处理.您可以添加某种变量,当每个工作线程到达wait()并且主线程不调用notifyAll()直到此变量达到5,或者您可以使用主线程循环并重复调用notifyAll()时,会增加某种变量.以便工作线程在多个组中发布.
看一下java.util.concurrent包 – 有几个锁类提供比基本同步锁更强大的功能 – 一如既往,Java可以让你免于重新发明轮子. CountDownLatch似乎特别相关.
总之,并发很难.您必须设计以确保当线程在您不想要的订单中执行时,一切仍然有效,以及您希望的订单.