避免Java编译器优化循环和if语句

时间:2014-05-21 11:13:19

标签: java multithreading

我有一个主题,其主要目的是处理列表中是否有项目。这是在循环中完成的:

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

            });
        }

    }

}

2 个答案:

答案 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;

实际上,这不是必要的。有更好的方法来做到这一点。例如。

  1. 更改jobsmessages或其他任何实现BlockingQueue的类。 (例如,ArrayBlockingQueue会给你一个有界的队列,如果你需要的话。

  2. 摆脱循环。

  3. 摆脱isEmpty测试。

  4. 通过拨打remove(0)来替换take()

  5. take()调用将阻塞,直到它成功从队列中删除somethinf ...或者当前线程被中断。在后一种情况下,将抛出InterruptedException

    这可能比在紧密循环中轮询中断的标志和队列更可靠,更有效率。