wait / notify的奇怪java行为
我发现java并发性的奇怪行为。 请参阅下面的代码:
public class Test { static CountDownLatch latch = new CountDownLatch(1); public static void main(String[] args) throws UnsupportedEncodingException, InterruptedException { final Thread t = new MyThread(); t.start(); synchronized (t) { latch.countDown(); System.out.println("got to sleep"); t.wait(); System.out.println("wake up"); } } static class MyThread extends Thread { @Override public void run() { try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (this) { System.out.println("inside run"); // notifyAll(); } } } }
以我的观点来看,这段代码应该挂起来等待,但是代码在控制台下一次完成时没有任何问题:
got to sleep inside run wake up
如果线程死了,我试图找到一些关于通知锁的信息,但是缺少它。 此外,我还没有在Java规范中找到任何信息。
但是如果我试图锁定其他对象(而不是线程对象),它就像我期望的那样工作正常。
这是因为你在等待一个Thread
实例。 Thread
内部使用wait
/ notify
/ notifyAll
,所以你不应该自己这么做 - 你会混淆Thread
, Thread
会混淆你。 特别是,当一个线程退出时,它会调用this.notifyAll()
。
从Thread.join
的文档:
这个实现使用this.wait
调用的一个循环,条件是this.isAlive
。 当一个线程终止this.notifyAll
方法被调用。 建议应用程序不要在Thread
实例上使用wait
, notify
或notifyAll
。
一般来说,尝试锁定并等待没有其他东西可以互动的对象。 这样,您可以推断对象上存在的并发相关操作,因为它们非常有限。 一旦任意代码可以在对象上同步(并且调用wait / notify等),就很难证明你的代码是正确的。 这就是为什么你会经常看到像这样的东西:
public class Foo {
private final Object lock = new Object();
... code which uses synchronized(lock) ...
}
正如Jon Skeet写道,在Thread对象上同步是一个坏主意,请使用另一个:
public class Test {
static CountDownLatch latch = new CountDownLatch(1);
static final Object sync = new Object();
public static void main(String[] args) throws UnsupportedEncodingException, InterruptedException {
final Thread t = new MyThread();
t.start();
synchronized (sync) {
latch.countDown();
System.out.println("got to sleep");
sync.wait();
System.out.println("wake up");
}
}
}
static class MyThread extends Thread {
@Override
public void run() {
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (sync) {
System.out.println("inside run");
//sync.notifyAll();
}
}
}
现在,除非您取消注释sync.notifyAll();否则此代码将永不结束。
链接地址: http://www.djcxy.com/p/91971.html