【问题标题】:Infinite loop in runnable goes out?可运行的无限循环消失了吗?
【发布时间】:2016-05-17 00:08:40
【问题描述】:

一些简化的代码来说明我的问题:

public class QueriesQueueRunnable implements Runnable {

    private List<String> queue = new ArrayList<String>();


    @Override
    public void run() {
        while(true){
            if (!this.getQueue().isEmpty()) {
                    System.out.println(this.getQueue().get(0));
                    this.getQueue().remove(0);

            }
        }
    }
}

QueriesQueueRunnable queriesQueueRunnable = new QueriesQueueRunnable();
Thread thread = new Thread(queriesQueueRunnable).start();




for (int i = 0; i < 1000; i++) {
     if(i==500){
         try {
                Thread.sleep(5000);                 
            } catch(InterruptedException ex) {
                Thread.currentThread().interrupt();
            }
     }
    queriesQueueRunnable.getQueue().add(String.valueOf(i));
}

输出仅在 i==499 迭代之前显示。为什么?这就像执行超出了可运行循环。

Java 1.7

【问题讨论】:

  • 你等了整整五秒钟吗?是否有任何错误消息,或者它只是挂起?
  • Thread thread = new Thread(queriesQueueRunnable).start(); 是编译错误。
  • 我已经等了五秒钟,是的。没有任何错误。输出在 499 处停止。

标签: java multithreading loops queue runnable


【解决方案1】:

当您的代码是sleeping 时,另一个线程无休止地旋转,毫无结果,使其容易受到 JIT 编译器的优化。由于该线程无法知道 queue 正在更新,因此优化器假定 queue.isEmpty() 将永远返回 true 并完全跳过检查。

避免这个问题的一种方法是使queue字段volatile,它通知JVM其他线程可以同时修改值:

private volatile List<String> queue = new ArrayList<String>();

请注意,尽管这将解决您的特定问题,但您的代码仍远非线程安全,因为ArrayList 并不意味着并发访问。

还请注意,您的程序永远不会完成,除非您将辅助线程设为 daemon thread

【讨论】:

  • 那我应该使用 Vector 和 synchronized 来使我的代码线程安全吗?
  • @user2132478 如果使用同步,则不需要 Vector,但如果使用 Vector,则仍需要围绕 if-then 逻辑进行同步。但是您可能最好使用 java.util.concurrent 包中的并发队列。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-12
  • 2022-11-19
  • 1970-01-01
  • 2011-02-24
  • 1970-01-01
  • 1970-01-01
  • 2011-11-28
相关资源
最近更新 更多