下面是我写的一段关于java的wait与notify测试代码,从逻辑上觉得控制台是不会有error字符输出的。
但是在eclipse上运行时发现运行一段时间会输出一次error。
没有想明白为什么,求大佬帮忙解释一下原理!!!import java.util.concurrent.atomic.AtomicBoolean;public class TestWait implements Runnable{
public final static byte[] lock = new byte[0];
public static AtomicBoolean flag = new AtomicBoolean(true);

public static void main(String[] args) {
new Thread(new TestWait()).start();
while(true){
synchronized (lock) {
flag.compareAndSet(false, true);
lock.notify();
}
}
} @Override
public void run() {
while(true){
try {
synchronized (lock) {
flag.compareAndSet(true, false);
lock.wait();
if(!flag.get()){
System.out.println("error");
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

解决方案 »

  1.   

    理论上是有可能出现error的多线程  理论上是同时进行  但是 实际中会有一点点的时间差距
    当你 main线程  flag.compareAndSet(false, true);这条语句执行完之后而 notify还未执行之前
    线程TestWait 在这之间执行了flag.compareAndSet(true, false);  lock.wait();  导致值被覆盖为false,之后线程进入休眠   然后马上main线程又执行了notify唤醒线程  导致  出现error锁与钥匙不在同一个同步代码块内就会导致这个问题虽然你给lock加了锁 但是并不是同一把锁  在调用同一个资源前  该线程都是可以进入对应的锁的
      

  2.   

    这里的lock锁应该能避免这个情况的。在flag修改为true到notify执行的中间时间lock对象的锁是由main线程获得的。此时另一个线程会阻塞在synchronize(lock)去抢lock对象锁,直到notify代码块执行完毕后释放锁,才能获得lock锁进去执行flag变为false吧
      

  3.   

    Java 多线程 之 wait等待 线程实例http://www.verejava.com/?id=16992949250274
      

  4.   

    Java 多线程 之 wait等待 线程实例http://www.verejava.com/?id=16992949250274
      

  5.   

    补充一下新的发现,在这个代码逻辑上增加了时间戳,发现在出错之前notify代码块先执行完毕释放锁,然后wait代码块拿到锁开始执行,在调用wait时并没有进行阻塞继续向下执行打印输出释放锁,在wait代码块抢到锁到释放锁之间notify代码块没有执行过。
      

  6.   

    就是时间差的原因,你可以sleep(2) 再试试,就不会出现这情况了。我最近也发现有类似的情况,逻辑上怎么看都是对的,可运行的结果就是打不到预期。sleep或debug模式 就能运行正常了