我对并发感到困惑 - 我试图阻止消费者线程运行,如果生产者关闭但是如果消费者在take()上被阻止则会出现问题。我尝试添加一个posion药丸,使用布尔标志中断当前线程,但仍无济于事。
请有人帮忙告诉我哪里出错了。感谢。
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();
}
}
答案 0 :(得分:3)
与并发混淆 - 我试图阻止消费者线程运行如果生产者关闭但是如果消费者在take()上被阻止则会出现问题
如果您的问题是您的计划没有停止,我认为您错过了exec.shutdownNow()
的{{1}}。这将中断你的第一个线程,如果你将你的循环更改为:
ExecutorService
如果没有中断标志检查,线程将看不到任何中断。中断只是在线程上设置的标志。某些方法(如while (!stopped && !Thread.currentThread().isInterrupted()) {
和Thread.sleep(...)
)抛出BlockingQueue.take()
当线程被中断但您的消费者正在旋转并且从不调用InterruptedException
。
真的,消费者中的旋转循环是一个非常糟糕的模式。它应该只调用take()
然后使用中断或让你的生产者实际提交一个中毒的药丸。类似的东西:
queue.take()
如果你正确使用中断,你真的不需要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");
}
标志。
你提到尝试了“中毒丸”。对于其他人来说,当你在队列中放置一个特定的“特殊”对象时,一个有毒的药丸是消费者用来知道何时关闭的。以下内容应该有效:
stopped
最后,当您可以轻松使用时,您正在使用2个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);
个实例。我想这里的重点是只打断其中一个而不是FYI。您可以使用单个ExecutorService
来创建所需的线程数。
答案 1 :(得分:0)
您永远不会关闭exec
执行者,只关注exec2
,因此运行TestPoisonPill
的主题永远不会中断。