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