我有一个阻塞队列,生产者主线程在该队列上添加来自文件输入的任务。
我有n个消费者,只要有人有空,就会从阻塞队列中选择任务,并在队列中找到任务。
现在可能是我的主线程可以完成从输入源读取所有任务并将其插入队列的操作。但是我不想在那儿结束我的申请。相反,我想在所有输入都用尽以及各个子消费者完成之后,等待子消费者进程完成其任务,并且所有消费者都在队列中等待更多输入。然后,我要继续关闭该应用程序。那怎么办
我看到的所有示例都主要是无限次运行生产者和消费者的模拟,持续了n秒钟。这似乎是一个实际情况
最佳答案
最干净的解决方案是引入使使用者终止的特殊任务对象。这样的特殊对象通常称为毒丸。如果有n个使用者线程,则在从文件中读取所有实际任务时,将n个毒药放入队列中。将n个毒药排入队列后,我的主线程结束了。每个使用者终止后,所有线程都将完成,并且JVM进程将终止。
另一个不太优雅的解决方案是检查是否还有任务,然后通过共享boolean
变量(在下面的示例中称为end
)向消费者线程发出此事件已发生的信号。为了使从主线程所做的更改对使用者线程可见,必须将该变量标记为volatile
。否则,必须依靠传递其他内存障碍,例如synchronized
。使用此解决方案,使用者可能不会使用take()
从队列中获取任务,因为如果没有可用的任务,这样做会阻止它们(不确定在处理过程中是否会发生)。import java.util.concurrent.LinkedBlockingQueue;
public class ProducerConsumer {
static class Task {} // just something to represent the task
static volatile boolean end = false; // signal the consumers that they can stop
public static void main(String[] args) {
var tasks = new LinkedBlockingQueue<Task>();
(new Thread(() -> {
while (!end) {
var t = tasks.poll();
if (t != null) {
// process t
}
}
})).start(); // Consumer, several of them
// fill tasks from file...
// may be started after all tasks are read from the file
// check every second if there are still tasks in the queue
while (tasks.size() > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {}
}
end = true;
}
}
关于java - 生产者是一个主线程,并且有n个使用者在无限循环中运行,所有使用者都在阻塞队列上工作。如何关机,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62794489/