7

我有一个触发 2 个线程的应用程序,第一个启动另一个类来做一些处理,然后启动一个第三个类来做更多的处理。主类中的第二个线程应该等到第三类中的某个事件完成后再执行其工作。如何做到这一点?

我曾尝试实现等待/通知以在两个线程之间共享锁定对象,但从技术上讲,这不起作用,因为我发现很难。我可以在班级之间共享一个锁吗?请注意,第 3 类的实例在第 1 类中声明并作为参数传递给第 2 类。我还尝试在第三类中创建布尔值,告诉事件何时完成,然后轮询第二个线程,直到该值为真。这行得通,但不是很理想。actionListner 也是解决这个问题的更好方法吗?

4

5 回答 5

10

你遇到了什么问题?正如您所描述的,它应该可以工作。例如,您可以在第 3 个类上实现 2 个方法,这些方法保留一个标志,该标志从一个类中检查并使用实例作为锁从另一个类中设置:

boolean done = false;

public synchronized setDone() {

    done = true;

    this.notifyAll();
}

public synchronized waitUntilDone() {

     while (!done) {

        try {
             this.wait();

        } catch (InterruptedException ignore) {
             // log.debug("interrupted: " + ignore.getMessage());
        }
     }
}

(注意:从内存中输入,未使用 Java 编译检查)

原则上不this.需要等待和 notifyAll 之前,我发现在这种情况下包含它们更清楚。

于 2010-05-08T10:15:01.973 回答
4

使用初始值为 1 的 CountDownLatch。

处理完成后进行第 3 类调用 countDown()。然后调用线程可以调用 await(),这将阻塞直到处理完成。

于 2010-05-08T10:23:37.397 回答
4

您正在解决的问题可以通过使用ActionListener或使用共享的Queue.

只需选择任何会阻塞消费者的阻塞队列,直到队列中出现某些内容。简单、清晰且经过验证。

如果您需要更多,请查看http://akkasource.org/http://jcp.org/en/jsr/detail?id=166之类的项目(Java 7 中将默认包含)。

于 2010-05-08T10:40:58.957 回答
4

您想使用计数信号量。条件变量用于在监视器内调度线程。这不是你想要做的。

您创建一个计数信号量并将计数设置为零

// create a counting semaphore with an initial count of zero
java.util.concurrent.Semaphore s = new java.util.concurrent.Semaphore(0);

您将信号量传递给您的班级进行处理。完成后,它通过调用将计数增加到 1 s.release()

要在处理器完成之前阻塞线程,请调用s.aquire(). 该调用将导致您的其他线程阻塞,直到处理器调用s.release().

这是最简单的解决方案。

顺便说一句,s.aquire()并且s.release()是线程安全的,因此您不需要使用 synchronize 关键字。线程可以共享对信号量的引用并在不锁定的情况下调用其方法。

更新:

我将在这里回复您的评论,而不是发表新评论。

是的,在您的情况下,wait()/notify() 解决方案类似于使用信号量。用信号量重写 rsp 的解决方案,它看起来像:

java.util.concurrent.Semaphore s = new java.util.concurrent.Semaphore(0);

public setDone() {
    s.release();
}

public waitUntilDone() {
     s.aquire();
}

它更简单,您不需要不必要的锁(注意我从方法 decs 中删除了 synchronized 关键字。)。

条件变量(wait()/notify())和信号量之间有两个区别。

区别 #1:对 notify() 的调用可能会丢失,对 release() 的调用永远不会丢失

第一个区别是,如果没有线程通过调用 wait() 等待,则调用 notify() 将丢失。解决方法是在调用 wait() 之前检查条件。基本上,我们需要记住 notify() 是使用共享变量调用的,因此我们不会在 worker 调用 notify() 后意外调用 wait(),否则我们会死锁。无论调用acquire() 和release() 的顺序如何,计数信号量都有效,因为它们在内部维护一个计数。

区别#2:调用wait()会自动释放锁,调用acquire()不会

一些背景信息将在这里有所帮助。在您的程序中,boolean done = false; 变量是条件,但不是条件变量。令人困惑的术语,我知道。条件变量是具有操作 wait() 和 notify() 的变量。Java 中的每个对象都有一个隐藏在内部的条件变量和一个相应的锁。

所有条件变量都与锁相关联。在调用 wait() 和 notify() 之前,您必须获取锁(如果不这样做,您将得到运行时异常,请尝试一下)。一旦获得锁,调用 wait() 会自动释放锁,允许监视器内的另一个线程可能调用 notify()。有时,这正是您想要的,尝试用信号量模拟这种行为会复杂得多。

注意:我使用的是监视器的学术定义,它与监视器的 Java 定义完全不同。

于 2010-05-10T06:39:43.963 回答
0

我认为join()操作会适合这个目的

插图:

假设你有 2 个线程

thead1 -> 需要等待的线程。

thread2 -> thread1 必须等待的线程。

然后在thread1的代码中,在你想等待的地方,写

thread2.join()

希望这可以帮助!

于 2013-11-26T05:17:13.623 回答