[英]Concurrency Issue - Blocking Queue
I am confused with concurrency - i am trying to stop the consumer thread from running if the producer is shutdown but am having issues if the consumer is blocked on take(). 我对并发性感到困惑 - 我试图阻止消费者线程运行,如果生产者关闭但是如果消费者在take()上被阻止则会出现问题。 I have tried adding a posion pill, interruptung the current thread, using a boolean flag and still to no avail.
我尝试添加一个posion药丸,使用布尔标志中断当前线程,但仍无济于事。
Please can someone help advise where I am going wrong. 请有人帮忙告诉我哪里出错了。 Thanks.
谢谢。
public class TestPoisonPill implements Runnable {
private BlockingQueue<String> queue = new ArrayBlockingQueue<String>(1);
private volatile boolean stopped = false;
public void addToQueue(String event) throws InterruptedException{
System.out.println("in add to queue");
if(event != null){
try {
queue.put(event);
} catch (InterruptedException e) {
stopped = true;
queue.put("Poison");
System.out.println("Unable to add the event to the queue, order routing processing is stopped");
throw e;
}
}
}
@Override
public void run() {
while(!stopped){
try {
if(queue.size() > 0){
String string = queue.take();
System.out.println("taken " + string + "from the queue");
}else{
continue;
}
}
catch (InterruptedException e) {
stopped = true;
}
}
}
public boolean isStopped(){
return stopped;
}
protected BlockingQueue<String> getQueue() {
return queue;
}
protected void setBoolean(boolean b){
this.stopped = b;
}
public static void main(String[] args) throws InterruptedException{
ExecutorService exec = Executors.newSingleThreadExecutor();
final TestPoisonPill t = new TestPoisonPill();
exec.execute(t);
ExecutorService exec2 = Executors.newSingleThreadExecutor();
Runnable addTask = new Runnable() {
public void run() {
while (true) {
try {
t.addToQueue("hi");
Thread.sleep(100);
} catch (InterruptedException ex) {
System.out.println("add task interrupted ");
t.setBoolean(true);
break;
}
}
}
};
exec2.execute(addTask);
Thread.sleep(1000);
exec2.shutdownNow();
}
}
am confused with concurrency - i am trying to stop the consumer thread from running if the producer is shutdown but am having issues if the consumer is blocked on take()
与并发相混淆 - 我试图阻止消费者线程运行,如果生产者关闭但是如果消费者在take()上被阻止则会出现问题
If you problem is that you program is not stopping, I think you are missing an exec.shutdownNow()
on your first ExecutorService
. 如果您遇到的问题是程序没有停止,我认为您在第一个
ExecutorService
上缺少exec.shutdownNow()
。 This will interrupt your first thread, if you change your loop to be something like: 如果您将循环更改为以下内容,这将中断您的第一个线程:
while (!stopped && !Thread.currentThread().isInterrupted()) {
Without the interrupt flag check any interrupt will be not been seen by the thread. 如果没有中断标志检查,线程将看不到任何中断。 An interrupt is just a flag that is set on the thread.
中断只是在线程上设置的标志。 Certain methods (like
Thread.sleep(...)
and BlockingQueue.take()
) throw InterruptedException
when a thread is interrupted but your consumer is spinning and never calling take()
. 某些方法(如
Thread.sleep(...)
和BlockingQueue.take()
)在线程被中断但您的消费者正在旋转并且从不调用take()
时抛出InterruptedException
。
Really, the spin loop in the consumer is an extremely bad pattern. 真的,消费者的旋转循环是一个非常糟糕的模式。 It should just call
queue.take()
and then either use the interrupt or have your producer actually submit a poisoned pill. 它应该只调用
queue.take()
,然后使用中断或让你的生产者实际提交一个中毒的药丸。 Something like: 就像是:
while (!Thread.currentThread().isInterrupted()) {
String string;
try {
string = queue.take();
} catch (InterruptedException e) {
break;
}
// here is where you could check for a poison pill
// something like: if (string == STOP_PILL) break;
System.out.println("taken " + string + "from the queue");
}
You don't really need the stopped
flag if you are using interrupt appropriately. 如果你正确使用中断,你真的不需要
stopped
标志。
You mention having tried a "poisoned pill". 你提到尝试了“中毒丸”。 For others, a poisoned pill is when you put a specific "special" object on the queue which the consumer uses to know when to shutdown.
对于其他人来说,当你在队列中放置一个特定的“特殊”对象时,一个有毒的药丸是消费者用来知道何时关闭的。 Something like the following should work:
像下面这样的东西应该工作:
private static final String STOP_PILL = "__STOP_PLEASE!!__";
...
// the consumer removes from the queue
String string = queue.take();
// it tests to see if it a pill, == is better than .equals here
if (string == STOP_PILL) {
// the consumer should stop
break;
}
...
// to stop the consumer, the producer puts the pill into the queue
queue.put(STOP_PILL);
Lastly, you are using 2 ExecutorService
instances when you could easily use one. 最后,当您可以轻松使用时,您正在使用2个
ExecutorService
实例。 I guess the point here is to interrupt only one of them but FYI. 我想这里的重点是只打断其中一个而不是FYI。 You can use a single
Executors.newCachedThreadPool()
which will create the number of threads you need. 您可以使用单个
Executors.newCachedThreadPool()
来创建所需的线程数。
你永远不关机的exec
执行,只有exec2
,所以线程中运行你的TestPoisonPill
永远不会被打断。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.