【发布时间】:2017-03-01 12:33:05
【问题描述】:
我有一个 Calculator 线程来计算从 1 到 50 的数字之和,以及多个 Reader 线程在 Calculator 线程准备好后显示结果。我可以选择调用 notify() 和 notifyAll() 来向 Reader 线程发出计算结果已准备好显示的信号。在 Calculator 类的 LINE B 中,如果我调用 notifyAll() 方法,结果会按预期打印 4 次。但是当我只用 notify() 替换 LINE B 时,我仍然看到打印了 4 次的结果,这似乎不正确。据我了解,notify() 只会唤醒正在等待的线程之一,而不是全部。为什么我调用 notify 时所有线程都唤醒并打印结果?
public class ThreadWaitNotify {
public static void main(String[] args) {
Calculator c = new Calculator();
Reader r = new Reader(c);
Reader r2 = new Reader(c);
Reader r3 = new Reader(c);
Reader r4 = new Reader(c);
r.start();
r2.start();
r3.start();
r4.start();
try {
Thread.sleep(500L);
} catch (InterruptedException e) {
e.printStackTrace();
}
c.start();
}
}
阅读器类:
class Reader extends Thread {
Calculator c;
public Reader(Calculator c) {
this.c = c;
}
@Override
public void run() {
synchronized (c) {
try {
System.out.println(Thread.currentThread().getName() + " Waiting for calculations: ");
c.wait(); // LINE A
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " Total: " + c.getSum());
}
}
}
计算器类:
class Calculator extends Thread {
private int sum = 0;
@Override
public void run() {
synchronized (this) {
for (int i = 1; i <= 50; i++) {
sum += i;
}
notify(); // LINE B
}
}
public int getSum() {
return sum;
}
}
输出:
Thread-1 Waiting for calculations:
Thread-4 Waiting for calculations:
Thread-3 Waiting for calculations:
Thread-2 Waiting for calculations:
Thread-1 Total: 1275
Thread-2 Total: 1275
Thread-3 Total: 1275
Thread-4 Total: 1275
=======================
更新: 使用对象作为监视器/锁而不是线程实例会产生正确的行为。
更新了 ThreadWaitNotify 类:
public class ThreadWaitNotify {
public static void main(String[] args) {
Object monitor = new Object();
Calculator c = new Calculator(monitor);
Reader r = new Reader(c, monitor);
Reader r2 = new Reader(c, monitor);
Reader r3 = new Reader(c, monitor);
Reader r4 = new Reader(c, monitor);
r.start();
r2.start();
r3.start();
r4.start();
try {
Thread.sleep(500L);
} catch (InterruptedException e) {
e.printStackTrace();
}
c.start();
}
}
更新的阅读器类:
class Reader extends Thread {
Calculator c;
Object monitor;
public Reader(Calculator c, Object monitor) {
this.c = c;
this.monitor = monitor;
}
@Override
public void run() {
synchronized (monitor) {
try {
System.out.println(Thread.currentThread().getName() + " Waiting for calculations: ");
monitor.wait(); // LINE A
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " Total: " + c.getSum());
}
}
}
更新的计算器类:
class Calculator extends Thread {
private int sum = 0;
Object monitor;
public Calculator(Object monitor) {
this.monitor = monitor;
}
@Override
public void run() {
synchronized (monitor) {
for (int i = 1; i <= 50; i++) {
sum += i;
}
monitor.notify(); // LINE B
}
}
public int getSum() {
return sum;
}
}
【问题讨论】:
-
感谢您查看@OldCurmudgeon。代码已经贴在 ThreadWaitNotify 的 main 方法下。我正在创建 4 个 Reader 实例。
-
我不会说更新版本是“正确的”,因为您在这两种情况下都依赖于未记录的行为。在一种情况下,它似乎符合您对代码应该如何工作的想法,但这是巧合。您假设 wait 仅在另一个线程调用 notify 时返回是不正确的。
-
锁定
Thread是一种反模式。扩展Thread是一种反模式。 -
在调用
notify时必须返回一次对wait的调用,但也允许以任何感觉返回wait。
标签: java multithreading