Ali*_*Ali 11 java multithreading
我有一个计算器线程计算1到50之间的数字之和,以及一个计算器线程准备好后显示结果的多个Reader线程.我可以选择调用notify()和notifyAll()来通知Reader线程计算结果已准备好显示.在Calculator类的LINE B中,如果我调用notifyAll()方法,结果将按预期打印4次.但是当我用仅通知()替换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();
}
}
Run Code Online (Sandbox Code Playgroud)
读者课程:
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());
}
}
}
Run Code Online (Sandbox Code Playgroud)
计算器类:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
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
Run Code Online (Sandbox Code Playgroud)
======================
更新:使用对象作为监视器/锁而不是Thread实例会产生正确的行为.
更新了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();
}
}
Run Code Online (Sandbox Code Playgroud)
更新的阅读器类:
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());
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新的计算器类:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
Izr*_*ruo 11
这并不会notify()唤醒所有读者Threads,而是终结Calculator's Thread's.
直到现在我也不知道这种行为,但看起来终止Thread所有Threads等待它的人都会醒来.Thread.sleep()在结束时再扔另一个,Calculator.run()你会看到.
我刚刚意识到阅读John的答案,这是一个至关重要的区别.
误解存在于"等待它"这一短语中.A Thread确实会通知所有服务员,但它与Thread概念无关.
事实上,这是一种特殊的行为,特别是a Thread,只要它达到寿命的终点,就会通知所有等待Thread 对象本身的服务员.正如John已经指出的那样,这将发生在'after'之后的某个时刻Thread.exit(),因此在JVM中,因此与对象释放无关.
虽然这很可能是所描述错误的原因,但绝不应该依赖JVM内部发生的任何事情.事实证明,这种行为是一个明确的指标.
我原来的答案是错的.我刚刚浏览了本机代码,了解发生了什么.
当一个线程结束时,它实际上会通知退出线程监视器上的所有等待线程.同样,这是在本机级别,并且可以改变
thread.cpp - >
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
..... other code ....
// Notify waiters on thread object. This has to be done after exit() is called
// on the thread (if the thread is the last thread in a daemon ThreadGroup the
// group should have the destroyed bit set before waiters are notified).
ensure_join(this);
assert(!this->has_pending_exception(), "ensure_join should have cleared");
.... other code ....
Run Code Online (Sandbox Code Playgroud)
这是来自JDK 7的源代码,但是我无法想象这个功能会有很大的不同.