我有一个主题,其主要目的是处理列表中是否有项目。这是在循环中完成的:
while (!Thread.currentThread().isInterrupted()) {
if (!jobs.isEmpty()) {
final Job current = jobs.remove(0);
current.start();
}
}
虽然线程没有中断,但应检查列表中是否有作业,如果是,则应执行。
但是这个代码是由编译器(或JIT?)优化的,并且永远不会到达if语句的主体 - 即使以后有项目。如果我在if块之前添加一些方法调用它。循环是必要的,因为线程在ExecutorService
中运行,我希望能够停止执行。那么我该如何避免这种优化呢?
更新
这就是我基本上所做的:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
private final Worker worker = new Test.Worker();
private final ExecutorService producer = Executors.newSingleThreadExecutor();
public static void main(final String[] args) {
new Test().start();
}
public void start() {
producer.execute(new Runnable() {
@Override
public void run() {
final int cnt = 0;
worker.add("Message " + cnt);
try {
Thread.sleep(500);
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
});
worker.start();
}
public class Worker {
private final List<String> messages = new ArrayList<>();
private final ExecutorService consumer = Executors.newSingleThreadExecutor();
public synchronized void add(final String msg) {
messages.add(msg);
}
public synchronized void start() {
consumer.execute(new Runnable() {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.print("");
if (!messages.isEmpty()) {
System.out.println(messages.remove(0));
}
}
}
});
}
}
}
答案 0 :(得分:3)
你没有提出的问题,&#34;做我想做的事情的合理方法是什么?&#34;,是使用blocking queue或{ {3}}用于jobs
集合。您经常使用CPU时间来轮询您的jobs
集合并检查interrupted
标记。并发集合类具有在不经常使用CPU的情况下轮询集合的方法,并且它们将正确处理中断。
答案 1 :(得分:3)
首先,JIT编译器极不可能优化if
语句。如果是这样,那将是一个编译器错误。
更可能的解释是if
正文未被执行,因为条件永远不会true
;即jobs
队列(或其他)总是空的......根据isEmpty()
。
&#34; 如果我添加System.out.println(&#34;未中断&#34;);就在一切正常之前,控制台总是输出&#34;没有中断&#34; &#34;
这可能是由于其他原因造成的。例如,在循环中执行一些I / O可能意味着某些其他线程有机会将某些内容放入队列中。
&#34; 循环是必要的,因为线程在ExecutorService中运行,我希望能够停止执行。&#34;
实际上,这不是必要的。有更好的方法来做到这一点。例如。
更改jobs
或messages
或其他任何实现BlockingQueue
的类。 (例如,ArrayBlockingQueue
会给你一个有界的队列,如果你需要的话。
摆脱循环。
摆脱isEmpty
测试。
通过拨打remove(0)
来替换take()
。
take()
调用将阻塞,直到它成功从队列中删除somethinf ...或者当前线程被中断。在后一种情况下,将抛出InterruptedException
。
这可能比在紧密循环中轮询中断的标志和队列更可靠,更有效率。