Java 创建可取消线程是否需要AtomicBoolean?
我经常使用以下模式创建可取消线程:Java 创建可取消线程是否需要AtomicBoolean?,java,multithreading,atomic,volatile,Java,Multithreading,Atomic,Volatile,我经常使用以下模式创建可取消线程: public class CounterLoop implements Runnable { private volatile AtomicBoolean cancelPending = new AtomicBoolean(false); @Override public void run() { while (!cancelPending.get()) { //count }
public class CounterLoop implements Runnable {
private volatile AtomicBoolean cancelPending = new AtomicBoolean(false);
@Override
public void run() {
while (!cancelPending.get()) {
//count
}
}
public void cancel() {
cancelPending.set(true);
}
}
但我不确定cancelPending一定是原子布尔。在这种情况下,我们可以只使用普通布尔值吗?不,不能。因为如果在没有正确同步的情况下从另一个线程更改布尔值,那么这个更改对另一个线程是不可见的。您可以在本例中使用
valotile boolean
,使任何修改对所有线程都可见 不,你不能。因为如果在没有正确同步的情况下从另一个线程更改布尔值,那么这个更改对另一个线程是不可见的。您可以在本例中使用valotile boolean
,使任何修改对所有线程都可见 您可以使用易失性布尔值
,而不会出现任何问题
请注意,这仅适用于布尔值仅更改为特定值的情况(在本例中为true
)。如果布尔值可能随时更改为true
或false
,则您可能需要AtomicBoolean
来检测竞争条件并根据竞争条件采取行动
然而,你描述的模式有一种与生俱来的气味。通过在布尔值(volatile
或not)上循环,您可能会发现自己试图插入某种睡眠
机制,或者不得不中断线程
一个更干净的方法是将过程分成更精细的步骤。我最近发布了一个答案,涵盖了暂停可能感兴趣的线程的选项。您可以使用
volatile boolean
,而无需任何问题
请注意,这仅适用于布尔值仅更改为特定值的情况(在本例中为true
)。如果布尔值可能随时更改为true
或false
,则您可能需要AtomicBoolean
来检测竞争条件并根据竞争条件采取行动
然而,你描述的模式有一种与生俱来的气味。通过在布尔值(volatile
或not)上循环,您可能会发现自己试图插入某种睡眠
机制,或者不得不中断线程
一个更干净的方法是将过程分成更精细的步骤。我最近发布了一个答案,涵盖了暂停可能感兴趣的线程的选项。是的,你可以。您可以使用非易失性AtomicBoolean(依赖于其内置的线程安全性),也可以使用任何其他易失性变量
根据Java内存模型(),这两个选项都会产生一个正确同步的程序,其中cancelPending变量的读写不能产生数据竞争。是的,可以。您可以使用非易失性AtomicBoolean(依赖于其内置的线程安全性),也可以使用任何其他易失性变量
根据java内存模型(),两个选项都会产生一个正确同步的程序,其中取消注销变量的读写不能产生数据竞争。在这个上下文中使用一个易失性布尔变量是安全的,尽管有些人可能认为它是坏的实践。咨询一下原因 使用原子*变量的解决方案似乎是最好的选择,尽管与易失性变量相比,同步可能会引入不必要的开销 您还可以使用临界截面
Object lock = new Object();
@Override
public void run() {
synchronized (lock) {
if (cancelPending) {
return;
}
}
}
或同步方法
synchronized public boolean shouldStop() {
return shouldStop;
}
synchronized public void setStop(boolean stop) {
shouldStop = stop;
}
在这个上下文中使用一个易失性布尔变量是安全的,尽管有些人可能认为它是错误的实践。咨询一下原因
使用原子*变量的解决方案似乎是最好的选择,尽管与易失性变量相比,同步可能会引入不必要的开销 您还可以使用临界截面Object lock = new Object();
@Override
public void run() {
synchronized (lock) {
if (cancelPending) {
return;
}
}
}
或同步方法
synchronized public boolean shouldStop() {
return shouldStop;
}
synchronized public void setStop(boolean stop) {
shouldStop = stop;
}
不需要同时使用
volatile
和AtomicBoolean
。如果将cancelPending
变量声明为final
,如下所示:
private final AtomicBoolean cancelPending = new AtomicBoolean(false);
final
字段的JLS语义意味着不需要同步(或volatile
)。所有线程都将看到cancelPending
引用的正确值。国家:
“当一个对象的构造函数完成时,该对象被视为已完全初始化。只有在该对象完全初始化后才能看到对该对象的引用的线程才能确保看到该对象最终字段的正确初始化值。”
。。。但对正常场没有这样的保证;i、 e.非final
和非volatile
您也可以将cancelPending
声明为volatile boolean
。。。因为您似乎没有使用原子布尔的测试和设置功能
但是,如果使用非易失性
布尔值
,则需要使用同步
,以确保所有线程都能看到取消挂起
标志的最新副本。不必同时使用易失性
和原子布尔值
。如果将cancelPending
变量声明为final
,如下所示:
private final AtomicBoolean cancelPending = new AtomicBoolean(false);
final
字段的JLS语义意味着不需要同步(或volatile
)。所有线程都将看到cancelPending
引用的正确值。国家:
“当一个对象的构造函数完成时,该对象被视为已完全初始化。只有在该对象完全初始化后才能看到对该对象的引用的线程才能确保看到该对象最终字段的正确初始化值。”
。。。但对正常场没有这样的保证;i、 e.非final
和非volatile
您也可以将cancelPending
声明为volatile boolean
。。。因为你似乎没有使用t