繁体   English   中英

线程安全否定了AtomicBoolean get()作为while循环中的条件

[英]Thread-safe negated AtomicBoolean get() as a condition in a while loop

假设我有以下代码:

AtomicBoolean condition;
condition = new AtomicBoolean(false);
(...)
while(!condition.get()){
   // do some stuff
}

我知道condition.get()原子的 ,但是,还是!condition.get()原子?

我的意思是,如果一个Thread以原子方式读取布尔值,然后在应用之前中断它就会发生! 操作,以便另一个Thread进入循环之前? 如果是这种情况,使用如下函数会更好吗:

private synchronized boolean checkNegatedCondition(AtomicBoolean cond){
    return !cond.get();
}

(...)

while(checkNegatedCondition(condition)){
   // do some stuff
}

提前致谢。

一个必须在这里准确:

  • get()操作的结果应该是原子的,并且由于对任何原子类的“进一步”保证,它也保证对于查看同一对象的其他线程是“可见的”(在某种意义上说是原子的)所有** set *方法都是原子的 ,因此不可能get() “半集”的东西)
  • 而! 操作是以任何方式保护

而且可以肯定:这里的核心问题不是 “原子性” - 因为get()只返回一个值(与double相反,甚至只有一个位/字节受影响)。 换句话说: AtomicBoolean主要是为了确保使用该对象的所有线程都可以看到对象的更改。

但是,是的, 假设 AtomicBoolean是一个类的字段 ,并且多个线程正在调用如下方法:

public void foo() {
  while(!condition.get() ...

理论上讲 ,这是可能的

  • 线程A“获取”错误
  • 线程B“设置”为真
  • 线程A计算计算! false - > true

但是:假设我们有一个“受保护的” getNot() ,最终结果将是相同的

  • 线程A“getNot”false - > true
  • 线程B“设置”为真

在这两种情况下,第一个线程都会进入循环!

原子性不是问题。 两个线程可以同时读取原子变量。 因此,任何数量的线程都可以读取该值并根据其否定进入循环。 如果没关系! 是原子的。 它作用于线程本地值。

要使用原子进行排除,通常需要AtomicBoolean.compareAndSet(boolean,boolean)

v.compareAndSet(a,b)只会将v设置为值b如果它是a并返回true。 否则如果v在开始时没有值a ,则它什么都不做并返回false。

在伪代码中它是

 synchronized public boolean compareAndSet(boolean a,boolean b){
      if(v!=a) return false;
      v=b;
      return true;
 }

但是(非常重要)以原子方式进行,因此v上的所有其他操作可以在它之前或之后进行排序。

AtomicBoolean condition = new AtomicBoolean(false);
//...
if(condition.compareAndSet(false,true)){
   //Only one thread can get here unless condition is set back...
}

如果你想将它用作'伪'同步块,你可能会编码:

while(!condition.compareAndSet(false,true));
   //Only one thread can get here at a time...
 condition.set(false);

这可以被描述为'锁定'。 因为线程'等待'进入受控部分'旋转'在循环中四舍五入直到释放。 这可能表现出比synchronized更差的性能,因为该操作系统通常会“暂停”等待线程并执行其他任务。 然而,在争用非常低的情况下(即需要很少或不需要等待),自旋锁可以表现出更好的性能。

Pro-Tip:在实践中,最好将condition.set(false) in a finally`块中:

while(!condition.compareAndSet(false,true));
try {
   //Only one thread can get here at a time...
 }finally{
     condition.set(false);
 }

否则,在一个线程中抛出的异常将永久lock out对该部分代码的任何访问。

AtomicBoolean.get不是关于原子的,而是关于线程安全的。

原子将是一个与读写东西相关的概念,你的问题没有提到这样的东西。

如果你想原子地读写(或写和读),AtomicBoolean上有其他方法(比如getAndSet或compareAndSet)。 从您的问题看,您可能正在寻找与此更相关的内容(无法从您的问题详细信息中确定)。

如果您想要的不是以原子方式检索和更改值,而是检索直到在某些逻辑之后在代码的其他位置更改它(因此不是原子地),那么您正在寻找锁定。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM