Java Runnable won';使用阻止队列时,请不要停止
我有一个Runnable,即使条件设置为停止,它也不会停止。不知道为什么会这样。有时,一些线程仍处于活动状态,而另一些线程则不处于活动状态。我让它运行了一个多小时,看它是否会停止,但它没有。这和我传递论点的方式有关吗Java Runnable won';使用阻止队列时,请不要停止,java,multithreading,queue,runnable,Java,Multithreading,Queue,Runnable,我有一个Runnable,即使条件设置为停止,它也不会停止。不知道为什么会这样。有时,一些线程仍处于活动状态,而另一些线程则不处于活动状态。我让它运行了一个多小时,看它是否会停止,但它没有。这和我传递论点的方式有关吗 public class ParserWorker implements Runnable { private BlockingQueue<String> queue = null; private ZipReader zip = null;
public class ParserWorker implements Runnable {
private BlockingQueue<String> queue = null;
private ZipReader zip = null;
public ParserWorker(BlockingQueue<String> queue, ZipReader zip) {
this.queue = queue;
this.zip = zip;
}
@Override
public void run() {
try {
while (!queue.isEmpty() || !zip.isClosed()) {
String line = queue.take();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
问题在于
解析器
类中的while
循环。我所指的是:
while (!queue.isEmpty() || !zip.isClosed()) {
String line = queue.take();
}
使用这段代码,您会遇到并发问题。调用BlockingQueue
的take
方法时,可能会发生两种情况:
String line=queue.take()代码>和!queue.isEmpty()
同时执行,没有并发问题。但是,以下情况可能发生(在您的情况下确实发生):
队列中只有一个元素
两个线程检查是否!queue.isEmpty()同时执行
。对于这两个线程,返回值都是true
,因为队列不是空的
第一个(更快的)线程调用queue.take()
并获取这个元素,然后再次检查while
条件并终止,因为队列仍然为空
第二个(较慢的)线程在空队列上调用queue.take()
,因为第一个线程已经从队列中获取了元素。因此,线程会阻塞,直到将新元素放入队列。然而,在某些情况下,这种情况在您的场景中永远不会发生,因为所有的行都被读取。这意味着线程将永远被阻塞,因为没有其他线程会为其放置元素
有很多解决方案可以解决这个问题。一个简单的方法就是改变
while (t1.isAlive() || t2.isAlive() || t3.isAlive() || t4.isAlive()) {
System.out.println("T1 alive:" + t1.isAlive() + ", T2 alive:" + t2.isAlive() + ",T3 alive:" + t3.isAlive() + ",T4 alive:" + t4.isAlive());
Thread.sleep(5000);
}
到
使用行queue.put(“”)代码>确保在所有线程终止之前放置元素。在您的情况下,此操作最多执行3次。这不是最合适的解决方案,它使线程读取空字符串,但它是最简单的解决方案。如果这不起作用,您可以花一些时间想出其他适合您需要的同步
另一种解决方案可以使用队列作为锁来使用额外的同步:
while (!queue.isEmpty() || !zip.isClosed()) {
synchronized (queue) {
if(!queue.isEmpty()) {
String line = queue.take();
}
}
}
通过这种方式,可以确保对每个线程一起执行队列是否为空的检查,以及在不为空的情况下获取元素,这样就不会有线程尝试弹出空队列。你必须决定你喜欢哪种方法。第二个需要额外的同步,但不会强制线程弹出空字符串。看起来您从未关闭“zip”,因此“zip.isClosed()”将始终为false我已包含ZipReader类,我相信当到达文件结尾时,它将关闭。请尝试打印以查看您的假设是否正确。您的zip.isEmpty()
方法的定义在哪里?或者你的意思是queue.isEmpty()
?@IvayloToskov-进行了更正。谢谢。谢谢,我刚刚加入了ZipReader类来澄清。您会注意到,当到达文件结尾时,在“finally”语句中,将“closed”设置为“true”,而不是使用queue.take()
我决定使用queue.poll()
并处理空值。感谢您的帮助。这让我明白了很多。
while (!queue.isEmpty() || !zip.isClosed()) {
String line = queue.take();
}
while (t1.isAlive() || t2.isAlive() || t3.isAlive() || t4.isAlive()) {
System.out.println("T1 alive:" + t1.isAlive() + ", T2 alive:" + t2.isAlive() + ",T3 alive:" + t3.isAlive() + ",T4 alive:" + t4.isAlive());
Thread.sleep(5000);
}
while (t1.isAlive() || t2.isAlive() || t3.isAlive() || t4.isAlive()) {
System.out.println("T1 alive:" + t1.isAlive() + ", T2 alive:" + t2.isAlive() + ",T3 alive:" + t3.isAlive() + ",T4 alive:" + t4.isAlive());
queue.put("");
Thread.sleep(5000);
}
while (!queue.isEmpty() || !zip.isClosed()) {
synchronized (queue) {
if(!queue.isEmpty()) {
String line = queue.take();
}
}
}