Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/395.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Runnable won';使用阻止队列时,请不要停止_Java_Multithreading_Queue_Runnable - Fatal编程技术网

Java Runnable won';使用阻止队列时,请不要停止

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;

我有一个Runnable,即使条件设置为停止,它也不会停止。不知道为什么会这样。有时,一些线程仍处于活动状态,而另一些线程则不处于活动状态。我让它运行了一个多小时,看它是否会停止,但它没有。这和我传递论点的方式有关吗

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();
        }
      }
    }