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