【发布时间】:2020-05-24 03:06:00
【问题描述】:
我正在做一个读取计算机能耗的项目。对于某些背景,能量读数是在 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() 发生。它没有意识到这艘船已经航行并且永远被困在等待中。
我对为什么会发生这种情况是正确的吗?如果是这样,我该如何防止这种情况发生?是保证被跟踪代码至少运行一定时间的唯一解决方案吗?起初这听起来很合理,因为跟踪几微秒代码的能量消耗是没有意义的。但是,代码可能有一个异常导致它过早中止,所以我宁愿有一些方法来处理这种情况。还可以选择从我的 run() 方法的开头删除 exit = false; 行,但我把它放在那里是为了确保同一个对象可以用于在一个程序中多次不同时间收集能量。
这种情况有线程安全约定吗?
另外,你觉得EnergyReadingCollector这个名字怎么样?这不是我最喜欢的,但它似乎足够具有描述性,我想不出比这更好的了。接受建议:)
编辑:
我做了 cmets 所说的在自己的 reinit() 方法中将 exit 设置为 false 。它实际上更有意义,而且我还有其他可以放入其中的功能。从那以后没有任何问题,所以这可能是问题所在。谢谢!
【问题讨论】:
-
不要在 run 方法中初始化退出。如果您希望能够重用该实例,请创建一个重置方法,将退出变量重置为 false。
-
@ClaudioCorsi 关于不在
run中初始化exit是正确的。详情请看我的回答。如果其中一个答案有帮助,请考虑接受。
标签: java multithreading thread-safety