避免等待终止线程

时间:2014-12-18 19:22:23

标签: java multithreading

我遇到的问题是,在我打电话给wait()之前,有时候我开始使用的话题已经完成。这似乎导致我的程序等待不会再发生的事情(notify())。我怎样才能确保不要等待完成的线程?

void someFunction() {

  MyThread thread = new MyThread();

  thread.start();

  // .. some stuff that takes sometimes quite long

  synchronized(thread) {
    try {
      thread.wait();
    } catch(InterruptedException e) {
      // ..
    }
  }
}

4 个答案:

答案 0 :(得分:2)

如果您阅读了线程的JavaDocs,它会告诉您永远不会在Thread对象上使用wait, notify, or notifyAll。你应该使用join()

答案 1 :(得分:1)

您可以使用:

而不是wait()
thread.join()

但我不知道你情况的背景。

答案 2 :(得分:1)

您正在查看"丢失的通知"问题。 (即,你没有以正确的方式使用wait()。)

当您致电foo.wait()时,总是等待您可以明确测试的某些条件。例如,像这样:

boolean condition;

synchronized(foo) {
    while (! condition) {
        foo.wait();
    }
    doSomethingThatRequiresConditionToBeTrue();
}

当你做任何使条件成立的事情时,它应该是这样的:

synchronized(foo) {
    doSomethingThatMakesConditionTrue();
    foo.notify();
}

如果你做任何使条件失败的事情,它应该是这样的:

synchronized(foo) {
    doSomethingThatMakesConditionFalse();
}

请注意:

  1. 任何触及condition的代码都会被同步,并且始终在同一个对象上同步。

  2. 当条件为真时,foo.wait()无法被调用。

  3. 循环调用wait()

  4. Point(2)是至关重要的,因为如果没有其他线程等待通知,foo.notify()根本不做任何事情。任何人都在等待的通知是#34;丢失"。 foo对象不记得已通知。

    第(3)点很重要,原因有两个。主要的是,如果线程A调用foo.wait(),然后线程B使条件为true并调用foo.notify();当wait()调用最终在线程A中返回时,不能保证条件仍然为真。其他一些线程可能使条件再次为假。在许多应用程序中,这是一个非常真实的场景。

    第(3)点重要的另一个原因是,即使没有调用foo.notify(),Java语言规范也允许foo.wait()返回。这被称为“虚假唤醒”,并允许它发生,这使得在某些操作系统上实现JVM变得更加容易。

答案 3 :(得分:0)

调用线程上的等待有时会起作用,因为当一个线程终止时,它会向等待它的每个线程发送一个通知。但是如果线程在当前线程调用wait之前已经终止,则不会发生任何通知。

使用join的建议是正确的,James Large的答案是正确的,你的代码应该在一个带有条件变量的循环中等待。这正是join正在做的事情,如果你查看java.lang.Thread.join的代码(其中join不带参数默认为0,wait(0)表示等待没有超时):

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;
        }
    }
}

它有一个循环,它测试Thread的活动标志,如果是真,那么它继续等待。如果线程已经终止,那么线程将不会等待,因此当前线程在完成连接线程之后等待的情况不会发生。