【问题标题】:Where is notifyAll getting called at the end of Thread.join()在 Thread.join() 结束时调用 notifyAll 的位置在哪里
【发布时间】:2014-09-04 18:15:06
【问题描述】:

来自 jdk 1.7.0_45 Thread.join(long miilliseconds) 的实例方法通过使调用者线程在此线程的对象监视器上等待来工作。此外,javadoc 明确指出

As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait, notify, or notifyAll on Thread instances.

  public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wai t(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

我没有看到 notifyAll() 被调用,因此调用 join() 的线程获取了该线程对象的监视器

如果我在线程 t 上调用 t.join(0),那么我没有在我的 run() 代码中实现 notifyAll()。那么调用者线程如何(调用 t.join() 的线程得到通知)

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    API documentation 说(我的重点):

    最多等待几毫秒让该线程终止。超时 0 意味着永远等待。

    此实现使用以 this.isAlive 为条件的 this.wait 调用循环。 在线程终止时调用 this.notifyAll 方法。建议应用程序不要在 Thread 实例上使用 wait、notify 或 notifyAll。

    join 方法不负责通知,它是在等待的事情。

    通知将由负责终止线程的任何 JVM 代码完成。

    【讨论】:

    • 我没有在加入线程 t 的 run() 代码中实现 notifyAll。现在检查我的编辑
    • @Kumar:我认为我的答案是一样的,当线程死亡时,jvm 会触发它的通知。它在 jdk 实现中,在本机代码中。
    • 所以你是在告诉我,所有线程在死后都会放弃它们可能已同步的任何对象?
    • @Kumar:不确定我是否遵循。线程是被同步的东西。线程到达它正在执行的 run 方法的末尾,JVM 获取线程的锁并执行 notifyAll,然后它会释放锁并将线程发送到 GC。
    • @KumarAbhinav 您的 run() 方法不是线程调用堆栈的基础。您的 run() 方法由一个库例程调用,该库例程在您的 run() 方法返回后执行 notifyAll()。
    【解决方案2】:

    你必须先了解notify-wait mechanism。一个线程(在一个对象上)等待,直到另一个线程通知它。

    示例代码

    // in main thread
    Thread t1 = new Thread(..);
    t1.start();
    t1.join();
    

    Thread#start() 的实现是native。一旦Thread#run() 方法完成,无论是突然还是正常完成,都需要调用notifyAll()

    这是必需的,以便可以通知调用join() 的线程。

    在上面的例子中,当main线程调用join()时,它最终会执行

    wait(delay);
    

    t1 引用的Thread 实例上调用。这将导致main 线程阻塞,直到在同一个Thread 对象上调用notifynotifyAll,这是native 实现start 必须做的,即。调用this.notifyAll()(可能在native代码中实现)。

    这也是开发人员绝对不应该在Thread 实例上调用waitnotify 的原因,以免弄乱这个join 实现。

    【讨论】:

    • 您说“必须执行 start 的本机实现,即调用 this.notifyAll()”。我认为我们应该在加入线程的 run() 完成后调用 notifyall,并且只有在 start 完成时才会执行 run completed.so notifyall() 将从哪里调用?
    • @KumarAbhinav start 内部调用 run()。当run() 完成时,start(大概)调用notifyAll()
    猜你喜欢
    • 2015-09-14
    • 2011-07-02
    • 2013-01-28
    • 1970-01-01
    • 1970-01-01
    • 2013-10-26
    • 2021-11-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多