[英]synchronized, wait/notifyAll has to be on the same object, but why?
在尝试使用wait()
和synchronized
进行简单演示时,我突然想到了一件有趣的事情,下面的演示给了我意想不到的输出。
public class WaitZero {
private static AtomicInteger num = new AtomicInteger(0);
private static boolean consumed = false;
public static void main(String... args) throws Exception {
ThreadPoolExecutor threadPoolExecutor = getMyCachedThreadPool();
for (int i = 0; i < 5; i++) {
threadPoolExecutor.submit(WaitZero::send);
threadPoolExecutor.submit(WaitZero::receive);
}
threadPoolExecutor.shutdown();
threadPoolExecutor.awaitTermination(60, TimeUnit.SECONDS);
}
private static synchronized void send() {
try {
while (!isConsumed()) {
num.wait();
}
} catch (InterruptedException ignored) {
ignored.printStackTrace();
}
num.incrementAndGet();
System.out.println(Thread.currentThread().getName() + " number updated: " + num);
setConsumed(false);
num.notifyAll();
}
private static synchronized void receive() {
try {
while (isConsumed()) {
num.wait();
}
} catch (InterruptedException ignored) {
ignored.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " number received: " + num);
setConsumed(true);
num.notifyAll(); // ToDo: when to use notify?
// ToDo: what is monitor?
}
private static boolean isConsumed() {
return consumed;
}
private static void setConsumed(boolean consumed) {
WaitZero.consumed = consumed;
}
}
它的输出不稳定,但典型之一可以是
shared-pool-0 number received: 0
shared-pool-1 number updated: 1
shared-pool-0 number received: 1
shared-pool-1 number updated: 2
shared-pool-1 number received: 2
shared-pool-2 number updated: 3
虽然我期待的是
shared-pool-1 number received: 0
shared-pool-0 number updated: 1
shared-pool-3 number received: 1
shared-pool-2 number updated: 2
shared-pool-1 number received: 2
shared-pool-0 number updated: 3
shared-pool-2 number received: 3
shared-pool-3 number updated: 4
shared-pool-5 number received: 4
shared-pool-4 number updated: 5
当我在wait()/notifyAll()
上使用WaitZero.class
而不是num
时,会检索到正确的结果。
我已经阅读过,似乎总是必须在同一个对象上使用其中三个以确保正确性。
我的猜测:如果不是所有这些都在同一个对象上,那么notifyAll()
和同步锁之间存在特殊情况。 但它是什么?
任何帮助将不胜感激 ;)
在@JB Nizet、@Amardeep Bhowmick 等提出了许多幼稚的问题和大力帮助之后,我从Java 中如何使用 wait()、notify() 和 notifyAll() 中找到了一个简洁的句子? 准确说明原因。
wait()
方法被设计/用于放弃锁(因为某些条件不满足)让其他线程工作/合作; 一个典型的用例是发送者/接收者或生产者/消费者。
wait()
它告诉调用线程放弃锁并进入休眠状态,直到某个其他线程进入同一个监视器并调用
notify()
...wait()
方法实际上与同步锁紧密集成,使用了无法直接使用的功能从同步机制。
synchronized(lockObject) {
while( ! condition ) {
lockObject.wait();
}
//take the action here;
}
在这种情况下,问题可以简单地修复如下,或者只使用WaitZero.class
进行wait/notifyAll
。
public class WaitZero {
private static AtomicInteger num = new AtomicInteger(0);
private static boolean consumed = false;
public static void main(String... args) throws Exception {
ThreadPoolExecutor threadPoolExecutor = getMyCachedThreadPool();
for (int i = 0; i < 5; i++) {
threadPoolExecutor.submit(WaitZero::send);
threadPoolExecutor.submit(WaitZero::receive);
}
threadPoolExecutor.shutdown();
threadPoolExecutor.awaitTermination(60, TimeUnit.SECONDS);
}
private static void send() {
synchronized (num) {
try {
while (!isConsumed()) {
num.wait();
}
} catch (InterruptedException ignored) {
ignored.printStackTrace();
}
num.incrementAndGet();
System.out.println(Thread.currentThread().getName() + " number updated: " + num);
setConsumed(false);
num.notifyAll();
}
}
private static void receive() {
synchronized (num) {
try {
while (isConsumed()) {
num.wait();
}
} catch (InterruptedException ignored) {
ignored.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " number received: " + num);
setConsumed(true);
num.notifyAll(); // ToDo: when to use notify?
// ToDo: what is monitor?
}
}
private static boolean isConsumed() {
return consumed;
}
private static void setConsumed(boolean consumed) {
WaitZero.consumed = consumed;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.