Java - 为什么Thread#join(millis)无效?

时间:2018-02-15 07:44:44

标签: java multithreading

作为一名初级Java开发人员,在编写我的第一个多线程代码时,我记得想要在循环中使用Thread.join(millis),并在每次线程仍处于活动状态时进行记录。我很惊讶地看到join在没有让我知道返回原因的情况下返回,但认为它是某种原生的“魔法”,像我这样的菜鸟无法理解。

最近我又看了java.lang.Thread实现,当我正在阅读join的实现时,我又想知道 - 因为它只是等待isAlive条件,不是吗自然地使用线程的最后一个状态作为返回值,以便客户端代码不必在外面明确检查它?

    /**
     * Waits at most {@code millis} milliseconds for this thread to
     * die. A timeout of {@code 0} means to wait forever.
     *
     * <p> This implementation uses a loop of {@code this.wait} calls
     * conditioned on {@code this.isAlive}. As a thread terminates the
     * {@code this.notifyAll} method is invoked. It is recommended that
     * applications not use {@code wait}, {@code notify}, or
     * {@code notifyAll} on {@code Thread} instances.
     *
     * @param  millis
     *         the time to wait in milliseconds
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    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;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

我想答案可能很简单“是的,这是可能的,你应该问问原来的JDK实施者。”但是我希望有一个更有教育意义的答案,如果存在这样的话。

2 个答案:

答案 0 :(得分:2)

  

使用线程的最后一个状态作为返回值

是不自然的

“自然”不是我使用的词,但它本来是一个合理的选择。有很多合理的选择。

请记住,Java中有一些真正不自然的API设计。例如,java.util.Date获取/返回1900年后代表年份的年数,年份。同样,将1月表示为0月,将12月表示为11月。

谁知道那些选择浪费了多少小时的开发人员时间。至少Thread.join(long) void的事实不会误导你;你只需要做一些工作来找出你想知道的东西。

API的设计是a)很久以前,b)需要运送“东西”。它们并不完美,因为它们的设计没有事后的好处。很难正确地设计API,即使你已经完成了,也会有人说“我不喜欢它因为它不做X”,或者“我更喜欢它做Y”。 / p>

除非API实际证明有缺陷 - Thread.join(long)不是,因为你可以在它返回时调用Thread.isAlive() - 或者破坏它,没有真正的动机来解决它,特别是当你坚定地致力于保留像Java那样的向后兼容性。

答案 1 :(得分:1)

可能是因为没有过多地偏离Thread.join()而不想将isAlive()的可能陈旧的价值返回到不花太多时间在这样一个无关紧要的细节选择上。

考虑到它来自1.0,你从一个完全不同的角度判断这一点。由于向后兼容性(二进制,如果不是源代码),它没有改变,主要是:为什么要改变它?它没有被打破。