Java线程不响应volatile boolean标志
我是Java并发新手,遇到了一个非常奇怪的问题: 我从一个大文件中读取数据,并使用多个工作线程处理输入数据和一些复杂的字符串匹配任务。我使用LinkedBlockingQueue将数据传输到工作线程,并在工作类中使用volatile boolean标志在到达文件末尾时响应信号 但是,我无法使工作线程正确停止。该程序的CPU使用率最终几乎为零,但程序不会正常终止 简化代码如下。我已经删除了真正的代码,并用一个简单的字计数器替换它们。但效果是一样的。在处理整个文件后,工作线程不会终止,并且在主线程中将布尔标志设置为true 主修课 对为什么会发生这种情况有什么建议吗Java线程不响应volatile boolean标志,java,multithreading,Java,Multithreading,我是Java并发新手,遇到了一个非常奇怪的问题: 我从一个大文件中读取数据,并使用多个工作线程处理输入数据和一些复杂的字符串匹配任务。我使用LinkedBlockingQueue将数据传输到工作线程,并在工作类中使用volatile boolean标志在到达文件末尾时响应信号 但是,我无法使工作线程正确停止。该程序的CPU使用率最终几乎为零,但程序不会正常终止 简化代码如下。我已经删除了真正的代码,并用一个简单的字计数器替换它们。但效果是一样的。在处理整个文件后,工作线程不会终止,并且在主线程中
非常感谢。正如Dan Getz所说,您的工作人员等待元素可用,但队列可能为空 在代码中,您检查队列是否为空,但没有任何内容阻止其他工作人员在检查后读取元素并从元素中移除元素 如果队列只包含一个元素,并且t1和t2是两个线程 可能发生以下情况: t2.isEmpty(); // -> false t1.isEmpty(); // -> false t2.take(); // now the queue is empty t1.take(); // wait forever
这里有一个疯狂的建议,就因为我刚才一直在看API。试试原子布尔运算,看看会发生什么?显然,他们已经准备好并发了——我没有把这作为一个答案,因为我真的不知道结果会是什么。之所以会发生这种情况,是因为接管一个空队列会等待一个元素可用。请参阅的答案,以了解在仍使用take的情况下完成您尝试的操作的方法。
public class Worker implements Runnable
{
private LinkedBlockingQueue<String> dataQueue = null;
private volatile boolean isDone = false;
public Worker(LinkedBlockingQueue<String> dataQueue)
{
this.dataQueue = dataQueue;
}
@Override
public void run()
{
String temp = null;
long count = 0;
System.out.println(Thread.currentThread().getName() + " running...");
try
{
while(!isDone || !dataQueue.isEmpty())
{
temp = dataQueue.take();
count = temp.length() + count;
if(count%1000 == 0)
{
System.out.println(Thread.currentThread().getName() + " : " + count);
}
}
System.out.println("Final result: " + Thread.currentThread().getName() + " : " + count);
}
catch (InterruptedException e)
{
}
}
public void setIsDone(boolean isDone)
{
this.isDone = isDone;
}
}
t2.isEmpty(); // -> false
t1.isEmpty(); // -> false
t2.take(); // now the queue is empty
t1.take(); // wait forever
public void run()
{
String temp = null;
long count = 0;
System.out.println(Thread.currentThread().getName() + " running...");
try
{
while(!isDone || !dataQueue.isEmpty())
{
temp = dataQueue.poll(2, TimeUnit.SECONDS);
if (temp == null)
// re-check if this was really the last element
continue;
count = temp.length() + count;
if(count%1000 == 0)
{
System.out.println(Thread.currentThread().getName() + " : " + count);
}
}
System.out.println("Final result: " + Thread.currentThread().getName() + " : " + count);
}
catch (InterruptedException e)
{
// here it is important to restore the interrupted flag!
Thread.currentThread().interrupt();
}
}