Java线程等待和通知

10

我有两个线程。线程A正在从队列中取出一些元素,而线程B正在向队列中添加一些元素。

当队列为空时,我希望线程A能够进入休眠状态。

当线程B向队列中添加元素时,它应该确保线程A正在工作。在Java中怎么做呢?

2个回答

21

使用 BlockingQueue,它是:

一个支持等待队列变为非空以获取元素和等待队列中有空间可用时存储元素的 Queue

认真对待,不要试图在这里重新发明轮子。




(如果你必须使用 wait/notify,请阅读这个教程。但请节省自己的痛苦!)


2

以下是一些细节:

import java.concurrent.Executors;
import java.concurrent.ExecutorService;
...
ExecutorService executor = Executors.newFixedThreadPool(someNumberOfThreads);
...
executor.execute(someObjectThatImplementsRunnable);
...
executor.shutdownNow();

这就是Java较新的线程功能。Executor是一个线程池,其中包含一些NumberOfThreads。它由阻塞队列提供支持。所有线程都会休眠,除非有工作要做。当您使用execute()方法将Runnable对象推入队列时,该Runnable对象会在队列中等待,直到有可用线程来处理它。然后,就会调用它的run()方法。最后,shutdownNow()方法会向池中所有线程发出关闭信号。
现在比以前简单多了。
(还有很多变化,例如具有最小和最大线程数的池,或者在调用execute()时队列达到最大大小之前会阻塞线程的队列。)

请注意,这并不是您想要用于长期运行的线程。它更适用于当您有一些短任务需要处理时。例如,如果您有一个线程从队列中拉取事件,然后对这些事件进行某些操作,那么从队列中拉取事件的线程可能不应该被池化,但它可以使用线程池来同时处理每个事件。您永远不希望池化线程等待某些东西,特别是在固定大小的池中。 - Adam Jaskiewicz
有趣。我很好奇这背后的原因是什么。我们在应用程序中有几个地方正在做你所警告的事情,我很好奇那会给我们带来什么麻烦。 - Clint Miller
线程池有两个主要目的:首先,通过重复使用线程来减少线程创建开销;其次,您可以控制同时给 CPU 处理的可运行任务数量。这两个目的对于像数字计算这样的 CPU 密集型任务以及其他想要并发运行的短期任务非常有用。像消费者线程这样的东西会一直等待,直到有东西可以消费,然后它会做自己的事情,然后回到等待状态。它的大部分时间都花在等待上,这意味着您的线程池中有一个不可用的线程。 - Adam Jaskiewicz
现在,如果您使用的是非固定大小的线程池,则这不是问题,但是那样您就会失去线程池的第二个目的:控制CPU绑定任务并发级别。您可以创建两个线程池;一个无限大小的线程池用于长期的、非CPU绑定的任务,该任务大部分时间都在等待系统的其他部分,以及一个固定大小的线程池用于短期任务,但前一种类型的线程实际上并不受线程池的好处,而且可以说“提交任务”的范例并不适用于具有类似应用程序本身寿命的内容。 - Adam Jaskiewicz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接