我遇到了阻止我正在创建的一些线程的问题。
代码
private volatile int status = STOPPED;
@Override
public void run() {
logger.info("Thread with ID : " + id);
status = RUNNING;
while (status == RUNNING) {
try {
execute(); //<-- very intensive
status = IDLE;
Thread.sleep(DYNAMIC_VALUE);
} catch (Exception e) {
logger.info("An exception occured in thread with ID : " + id);
e.printStackTrace();
} finally {
if(status == IDLE)
status = RUNNING;
}
}
logger.info("Thread with ID : " + id + " just exited.");
}
@Override
public void stop() {
status = STOPPED;
logger.info("Thread with ID: " + id + " is stopped.");
}
有时当我调用stop()
时,并非所有线程都在停止。
这从未被称为
logger.info("Thread with ID : " + id + " just exited.");
相反,execute()
内的日志消息会重复出现,因此无法获取
卡在路上的某个地方。这就像status
的值不会改变。
execute()方法是重量级的。它做了许多更新等事情 数据库和调用Web服务。
你是否看到我停止线程的方式有什么问题,或者我应该看看 更深的?我是否涵盖了这方面的内容?
答案 0 :(得分:8)
我建议使用Thread#interrupt()
而不是现在status
标志的双重角色(控制线程和报告状态)。这是Thread.sleep()
来电的完美匹配,它会自动抛出InterruptedException
。
如果您这样做,则无需更改status
标记在其报告角色中的运作方式,您可以在{{}}中删除任何提及的内容。 {1}}。
这种方法的一个好处是,您还可以在stop()
后面的代码中添加快速Thread#interrupted
检查,从而使您的线程更快停止;或者允许您在前往execute
之前一次完成更多工作。完全消除sleep
将成为另一个有趣的选择。
sleep
不是选项如果你找到一个很好的理由为什么中断机制对你不起作用,那么我会建议一些比interrupt
更复杂的东西,但同样有效且可以说更清洁:保持良好的设计理念让AtomicInteger
报告状态(您可以将其降级为status
并将其称为boolean
),并创建单独的 {{1对于active
控件。
答案 1 :(得分:5)
如果线程仍然是execute()
- 它们将不会停止,因为您之后将状态设置为IDLE,忽略之前的值。甚至在status = IDLE
之前添加支票也不会在所有情况下都有效。
我建议使用AtomicInteger
而不是volatile int并使用其compareAndSet
方法,即:
while (status.get() == RUNNING) {
try {
execute(); //<-- very intensive
if (!status.compareAndSet(RUNNING, IDLE))
break;
} catch (Exception e) {
logger.info("An exception occured in thread with ID : " + id);
e.printStackTrace();
} finally {
try {
Thread.sleep(DYNAMIC_VALUE);
} catch (InterruptedException e) {}
if (!status.compareAndSet(IDLE, RUNNING))
break;
}
}
您应该在将状态设置为STOPPED后中断线程,以便在适用的情况下中断sleep
。
答案 2 :(得分:2)
如果在设置status = STOPPED时线程中正在运行execute(),则线程将在从execute()返回时设置status = IDLE,然后finally块将设置status = RUNNING,并且你的循环环路。
答案 3 :(得分:1)
在最终状态中,你使它运行,它可能会导致问题,当你在状态到达之前使它停止时,它可以再次运行。
答案 4 :(得分:1)
使用您当前的设计,您可以在try块的中间以及finally块的中间设置状态值之前检查状态值。
干杯