java - 了解 Java 线程中的等待

标签 java multithreading wait java-threads

我有以下代码:-

class ThreadB extends Thread {
    int total;

    @Override public void run() {
        synchronized (this){
            for(int i=0; i<5; i++){
                total+=i;
            }
        }
    }
}

public class Solution {
    public static void main(String[] args) throws InterruptedException {
        ThreadB b = new ThreadB();
        b.start();
        synchronized (b){
            b.wait();
        }
        System.out.println(b.total);
    }
}

每当我运行这个程序时,我得到的输出都是 10。 如果我注释等待线,我得到的输出始终为 0。

我很困惑为什么我得到的答案总是 10。 有 2 个线程,ThreadB 和主线程,因此当我执行 wait 方法时,ThreadB 应该根据定义等待,并且不应添加值,因此主线程应该打印 0?

最佳答案

每个对象都有一个内部锁,线程可以使用同步来获取该锁。当线程无能为力时调用 wait,直到发生变化(例如, 它可能试图插入到当前已满的有界队列中),它对通过synchronized 获取其锁的对象调用 wait 。当主线程调用b.wait()时,意味着主线程进入 hibernate 状态。

当代码中的wait被注释掉时,ThreadB线程仍在启动过程中,主线程可以获得锁,然后在ThreadB获得锁之前释放锁并打印total,此时total仍为0 . 从技术上讲,存在竞争,并且不能保证哪个线程先执行,但主线程有一个良好的开始。

当代码使用 wait 时,主线程将获取 ThreadB 上的锁(再次先于 ThreadB 到达那里),然后等待,直到收到通知。当线程终止时,它会导致调度程序通知其等待集中的任何线程,因此当 threadB 完成时,它会导致主线程唤醒并从那里继续。由于 ThreadB 已完成,当主线程开始打印它时,总数已达到 10。

如果主线程没有在 ThreadB 之前获得锁,那么(因为 ThreadB 在其运行的整个过程中都持有该锁)它在 ThreadB 完成之前无法获取锁。这意味着当垂死的线程发送通知时它不在等待集中,但会稍后等待,并且不会有任何通知唤醒它并且它会挂起。

这种问题(导致通知丢失和线程挂起的竞争)在错误使用 wait/notify 时可能会发生。有关使用等待和通知的正确方法,请阅读 https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html .

如果您特别希望一个线程等待另一个线程完成,Thread 有一个名为 join 的实例方法用于此目的,主线程将在此处调用该方法,如下所示

b.join();

顺便说一句,终止通知行为记录在 the api doc for java.lang.Thread#join 中,它说:

This implementation uses a loop of this.wait calls conditioned on this.isAlive. As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait, notify, or notifyAll on Thread instances.

请注意针对 Thread 对象进行同步的警告。它与 JDK 代码(例如锁定线程的 join)配合不佳。

关于java - 了解 Java 线程中的等待,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71247244/

相关文章:

c++ - 单个进程中的死锁 -?

java - 提交并等待 ExecutorService 终止的正确方法

Java StringBuilder 类,为什么多了 16 个空元素?

java - 打印 PDF 时反转阿拉伯语

ios - UI 未在主线程中更新

node.js - Nodejs Childexec 对文件中的每一行执行命令,但等待第一个命令退出,然后再运行下一个命令

java - java多线程的具体问题

c++ - Qt4 小部件 : implementing a wait function without blocking the widget

java - XML 格式的背景图像

java - .net 中 AggregateException 的 java 等价物是什么?