首页 > 解决方案 > 如何确保 Java 线程永远不会运行无限循环?

问题描述

我正在做一个读取计算机能耗的项目。对于某些背景,能量读数是在 C 中的低级别完成的,但我正在开发一个 Java 应用程序,该应用程序使用本机调用来获取读数,然后用它们做一些更高级别的事情。

我现在正在做的是制作一个EnergyReadingCollector作为线程运行的对象,抓取并存储读数,直到你告诉它停止。您可以在其他一些代码运行时使用它,然后在最后您有一堆关于程序如何消耗能量的数据。制作一些漂亮的图表来打动女士们,你知道;)

当您跟踪的代码部分非常快时,就会出现我的问题。长时间拉伸不会出现问题,但有时我的程序会在快速位上运行无限循环。

这是我的课。我遗漏了很多细节,因为这个问题只与这个程序的线程方面有关。我认为这足以说明正在发生的事情。

public class EnergyReadingCollector implements Runnable
{
    private ArrayList<double> readings;
    private volatile boolean exit = false;

    public void run()
    {
        readings.clear();
        exit = false;
        while (!exit) {
            double reading = getReading();
            readings.add(reading);
        }
    }

    public void end()
    {
        exit = true;
    }

}

简单用例:

EnergyReadingCollector ec = new EnergyReadingCollector();
new Thread(ec).start();
//code section to track
ec.end();

ec对象现在有一个内部存储的列表,其中包含在此代码部分中发生的所有能量读数。

我认为会发生无限循环,因为快速代码甚至在线程开始之前就结束了。所以它执行并ec.end()发生,但随后线程启动并等待ec.end()发生。它没有意识到船已经航行并且永远被困在等待中。

我对为什么会发生这种情况是正确的吗?如果是这样,我该如何防止这种情况发生?是保证被跟踪代码至少运行一定时间的唯一解决方案吗?起初这听起来很合理,因为跟踪几微秒代码的能量消耗是没有意义的。但是,代码可能有一个异常导致它过早中止,所以我宁愿有一些方法来处理这种情况。还可以选择从我的方法开头删除该exit = false;run(),但我将其放在那里以确保同一对象可用于在一个程序中多次不同时间收集能量。

这种情况是否有线程安全约定?

另外,你觉得这个名字EnergyReadingCollector怎么样?这不是我最喜欢的,但它似乎足够具有描述性,我想不出比这更好的了。接受建议:)

编辑:我做了评论中所说exit的以自己的reinit()方法设置为 false 的内容。它实际上更有意义,而且我还有其他可以放入其中的功能。从那以后没有任何问题,所以这可能是问题所在。谢谢!

标签: javamultithreadingthread-safety

解决方案


问题是它exit不是易变的。因此,在将值设置为 true 和读取值之间的关系之前没有发生任何事情。

JIT 可以决定将值的读数提升到循环之外:

if(exit) return;
while(true){
   .. stuff
}

推荐阅读