Java 使用volatile停止线程
我在停止正在创建的一些线程时遇到问题 代码Java 使用volatile停止线程,java,multithreading,volatile,Java,Multithreading,Volatile,我在停止正在创建的一些线程时遇到问题 代码 private volatile int status = STOPPED; @Override public void run() { logger.info("Thread with ID : " + id); status = RUNNING; while (status == RUNNING) { try { execute(); //<-- very intensiv
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.");
}
相反,execute()
中的日志消息会重复出现,因此不会被删除
在路上的某个地方卡住了。这就像status
的值不会改变一样
execute()方法是重量级的。它可以做很多事情,比如更新
数据库和调用web服务
你认为我停止线程的方式有什么问题吗?或者我应该看看吗
更深的?我是否介绍了这方面的内容?如果在设置status=STOPPED时,execute()正在线程中运行,那么从execute()返回时,线程将设置status=IDLE,然后finally块将设置status=running,并且循环循环。在finally状态下,如果使其运行,则会导致问题,当您在while条件出现之前使其停止时,它可以再次运行。如果线程仍然处于
execute()
-ing状态,则它们不会停止,因为您刚刚将它们的状态设置为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;
}
}
while(status.get()==正在运行){
试一试{
execute();//我建议使用Thread#interrupt()
而不是现在为status
标记使用双重角色(控制线程和报告状态)。这与Thread.sleep()调用非常匹配,它将自动抛出InterruptedException
如果您这样做,您不必更改您的状态
标志在其报告角色中的运行方式,您可以在stop()
中删除对它的任何提及
这种方法的一个好处是,您还可以在执行后的代码中添加一个快速的线程#中断的检查,从而使线程停止得更快;或者允许您在进入睡眠之前一次做更多的工作这将成为另一个有趣的选择
如果中断不是一个选项
如果您找到了中断机制不适用于您的一个很好的理由,那么我建议使用比原子整数
更不复杂的方法,但同样有效且可以说更干净:保留好的设计思想,让状态
报告状态(您可以将其降级为“代码> BooLoe<代码>,并调用它>代码> Active < /COD>),并为<<代码>运行< < /Cord>控件>创建一个单独的<代码>布尔< /代码> .< /p> 使用当前的设计,在将其设置在尝试块的中间以及最后块的中间之前,可以检查状态值。
干杯+1您还可以将状态
设置为枚举
并使用原子引用
。这不会改变线程问题,只会使状态
更加类型安全和Java惯用。:)该死,我错过了。感谢您提供了比我要求的更多。投票通过并接受了。我考虑过使用中断(),但是如果一个线程在等待web服务响应时被卡住了该怎么办呢?我不希望它立即退出,我希望先完成整个循环,然后退出。你的想法?哦,当然,我投了赞成票。谢谢你的帮助。你必须检查你的I/O是否是可中断的——例如,java.io
不是,而java NIO我认为不是实际上,这里有两种选择。如果您发现它是可中断的,那么您将不得不继续使用当前的手动模式。但是,在这种情况下,我会建议一些不太复杂但同样有效的方法:保留好的设计思想,让状态
报告状态(您可以将其降级为布尔值,并称之为活动的),然后为运行的控件创建一个单独的布尔值。我喜欢这些设计建议。我会遵循它们。再次感谢。
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;
}
}