Java BlockingQueue在take()上阻塞,稍微有点扭曲
我有两个阻塞队列的情况。首先,我插入一些我执行的任务。当每个任务完成时,它会将一个任务添加到第二个队列中,在那里执行任务 所以我的第一个队列很简单:我只是检查确保它不是空的,然后执行,否则我会中断() 我做的第二件事,正如你所知,是行不通的:Java BlockingQueue在take()上阻塞,稍微有点扭曲,java,concurrency,blockingqueue,Java,Concurrency,Blockingqueue,我有两个阻塞队列的情况。首先,我插入一些我执行的任务。当每个任务完成时,它会将一个任务添加到第二个队列中,在那里执行任务 所以我的第一个队列很简单:我只是检查确保它不是空的,然后执行,否则我会中断() 我做的第二件事,正如你所知,是行不通的: public void run() { try { SomeTask2 task2 = taskQueue2.take(); doTask(task2); } catch (InterruptedE
public void run() {
try {
SomeTask2 task2 = taskQueue2.take();
doTask(task2);
}
catch (InterruptedException ex) {
}
Thread.currentThread().interrupt();
}
如何解决该问题,使第二个BlockingQueue不会在take()上阻塞,但只有在它知道没有更多项要添加时才会完成。如果第二个线程可以看到第一个阻塞队列,并检查该队列是否为空,第二个队列是否也为空,那么它将中断
我也可以使用有毒物品,但我更喜欢其他东西
注意:这不是确切的代码,只是我在这里写的一些东西:我不知道您在这里实际想做什么,但我可以说,您的第一个
run()
方法中的interrupt()
要么毫无意义,要么是错误的
- 如果您正在自己的
对象中运行Thread
方法,那么该线程无论如何都将退出,因此没有必要中断它run()
- 如果在具有线程池的执行器中运行
方法,则很可能根本不想终止线程或关闭执行器。。。在那一点上。如果确实要关闭执行器,则应调用其关闭方法之一run()
例如,这里有一个版本,没有所有的中断内容,也没有线程创建/破坏搅动,你看起来在做什么
public class TaskExecutor {
private ExecutorService executor = new ThreadPoolExecutorService(...);
public void submitTask1(final SomeTask task) {
executor.submit(new Runnable(){
public void run() {
doTask(task);
submitTask2(task);
}
});
}
public void submitTask2(final SomeTask task) {
executor.submit(new Runnable(){
public void run() {
doTask2(task);
}
});
}
public void shutdown() {
executor.shutdown();
}
}
如果要为任务单独排队,只需创建并使用两个不同的执行器即可 我不知道您在这里实际想做什么,但我可以说,您的第一个
run()
方法中的interrupt()
要么毫无意义,要么是错误的
- 如果您正在自己的
对象中运行Thread
方法,那么该线程无论如何都将退出,因此没有必要中断它run()
- 如果在具有线程池的执行器中运行
方法,则很可能根本不想终止线程或关闭执行器。。。在那一点上。如果确实要关闭执行器,则应调用其关闭方法之一run()
例如,这里有一个版本,没有所有的中断内容,也没有线程创建/破坏搅动,你看起来在做什么
public class TaskExecutor {
private ExecutorService executor = new ThreadPoolExecutorService(...);
public void submitTask1(final SomeTask task) {
executor.submit(new Runnable(){
public void run() {
doTask(task);
submitTask2(task);
}
});
}
public void submitTask2(final SomeTask task) {
executor.submit(new Runnable(){
public void run() {
doTask2(task);
}
});
}
public void shutdown() {
executor.shutdown();
}
}
如果要为任务单独排队,只需创建并使用两个不同的执行器即可 听起来好像处理第一个队列的线程知道一旦队列耗尽,就不会有更多的任务出现。这听起来很可疑,但我会相信你的话,并提出一个解决方案 定义一个对两个线程都可见的
AtomicInteger
。将其初始化为正1
定义第一个线程的操作,如下所示:
- 在
队列上循环#poll()
- 如果
返回null,则对共享整数调用Queue#poll()
。AtomicInteger#decrementAndGet()
- 如果
返回零,则通过AtomicInteger#decrementAndGet()
中断第二个线程。(这将处理没有项目到达的情况。)thread#interrupt()
- 在这两种情况下,退出循环
- 如果
- 否则,处理提取的项,对共享整数调用
,将提取的项添加到第二个线程的队列中,然后继续循环AtomicInteger#incrementAndGet()
- 循环阻塞
阻塞队列#take()
- 如果
抛出BlockingQueue#take()
,捕获异常,调用InterruptedException
,然后退出循环Thread.currentThread().interrupt()
- 否则,处理提取的项目
- 对共享整数调用
。AtomicInteger#decrementAndGet()
- 如果
返回零,则退出循环AtomicInteger#decrementAndGet()
- 否则,继续循环
- 如果
有许多设计可以在这里工作。我只描述了一个只引入了一个额外实体的例子,即共享原子整数,但即使如此,它也很复杂。我认为使用毒丸会更干净,尽管我承认无论是
Queue#add()
还是BlockingQueue#put()
都不接受null作为有效元素(由于Queue#poll()
的返回值契约)。否则,很容易将null用作毒药。听起来好像处理第一个队列的线程知道一旦其队列耗尽,就不会有更多任务出现。这听起来很可疑,但我会相信你的话,并提出一个解决方案
定义一个对两个线程都可见的AtomicInteger
。初始化