gpt4 book ai didi

java - 如何确保 Java 线程永远不会运行无限循环?

转载 作者:行者123 更新时间:2023-12-01 16:39:45 26 4
gpt4 key购买 nike

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

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

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

这是我的类(class)。我省略了很多细节,因为这个问题只涉及该程序的线程方面。我认为这足以说明正在发生的事情。

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 这个名字有何看法?这不是我最喜欢的,但它似乎描述性足够,我想不出更好的了。接受建议:)

编辑:我做了评论中所说的关于在其自己的 reinit() 方法中将 exit 设置为 false 的操作。它实际上更有意义,而且我可以将其他功能放入其中。此后一直没有出现任何问题,所以可能是问题所在。谢谢!

最佳答案

开始阶段创建Runnable并启动线程,这是一个异步操作:

EnergyReadingCollector ec = new EnergyReadingCollector();
// Thread A: ec.exit = false;
new Thread(ec).start(); // Thread B: ec.exit = false;
// Thread B: while (!ec.exit) {

结束阶段设置标志:

ec.end();               // Thread A: ec.exit = true;

假设能耗“部分”中的代码执行时间接近于零,则可能发生以下事件顺序(丢失更新),这会导致无限循环:

// EnergyReadingCollector ec = new EnergyReadingCollector();
Thread A: ec.exit = false;
// new Thread(ec).start();
Thread A: ec.exit = true;
Thread B: ec.exit = false;
Thread B: while (!ec.exit) {

要解决这个问题,您需要做的就是删除 run() 中的初始化,这不是必需的,因为有一个用于 exit 的初始化程序。

请注意,您应该始终通过 Thread.join() 等待线程完成。否则,即使最后一个线程仍在运行,也可能会在后续的能耗部分启动新线程,这可能会导致达到资源限制。

回到exit的初始化。如果 Runnable 实例应该是可重用的,您可以在离开 run() 之前重置 exit。无论如何,在重用实例之前,您必须确保线程不再运行。 Thread.join() 会做到这一点。

关于java - 如何确保 Java 线程永远不会运行无限循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61884014/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com