runnable 中的无限循环消失了吗?
Infinite loop in runnable goes out?
一些简化的代码来说明我的问题:
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 迭代。为什么?就好像执行跳出了runnable loop
Java 1.7
当您的代码正在 sleep
ing 时,另一个线程正在无休止且毫无结果地旋转,使其容易受到 JIT 编译器的优化。由于该线程无法知道 queue
正在更新,因此优化器假定 queue.isEmpty()
将永远 return true
并完全跳过检查。
避免此问题的一种方法是使 queue
字段 volatile
,它通知 JVM 其他线程可以同时修改该值:
private volatile List<String> queue = new ArrayList<String>();
请注意,虽然这将解决您的特定问题,但您的代码仍然远非线程安全,因为 ArrayList
并不意味着并发访问。
另请注意,您的程序永远不会完成,除非您将辅助线程设置为 daemon thread。
一些简化的代码来说明我的问题:
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 迭代。为什么?就好像执行跳出了runnable loop
Java 1.7
当您的代码正在 sleep
ing 时,另一个线程正在无休止且毫无结果地旋转,使其容易受到 JIT 编译器的优化。由于该线程无法知道 queue
正在更新,因此优化器假定 queue.isEmpty()
将永远 return true
并完全跳过检查。
避免此问题的一种方法是使 queue
字段 volatile
,它通知 JVM 其他线程可以同时修改该值:
private volatile List<String> queue = new ArrayList<String>();
请注意,虽然这将解决您的特定问题,但您的代码仍然远非线程安全,因为 ArrayList
并不意味着并发访问。
另请注意,您的程序永远不会完成,除非您将辅助线程设置为 daemon thread。