2016-05-17 60 views
1

一些简化代码来说明我的问题:runnable中的无限循环熄灭?

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

+0

你等了五秒钟吗?是否有任何错误消息,或只是挂起? – Michael

+5

'线程线程=新线程(queriesQueueRunnable).start();'是一个编译错误。 – shmosel

+0

我已经等了五秒钟了。没有任何错误。输出只停在499. – user2132478

回答

0

当你的代码是sleep ING,另一个线程正在不断地和徒劳旋转,离开它容易受到JIT编译器优化。由于该线程无法知道queue正在更新,所以优化器假定queue.isEmpty()将永远返回true并完全跳过检查。为了避免这个问题

的一种方法是使queuevolatile,它通知JVM别人线程可以同时修改值:

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

注意的是,虽然这将解决您的具体问题,你代码仍然远离线程安全,因为ArrayList并不意味着并发访问。

另请注意,除非您使辅助线程为daemon thread,否则您的程序将永远不会完成。

+0

非常感谢! – user2132478

+0

然后,我应该使用向量和同步,使我的代码线程安全? – user2132478

+0

@ user2132478如果使用同步,则不需要Vector,但如果使用Vector,则仍然需要围绕if-then逻辑进行同步。但是,您可能更适合使用[java.util.concurrent]中的并发队列(https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html )包。 – shmosel