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

时间:2017-08-14 11:52:47

标签: java multithreading

假设我有以下代码:

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

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

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

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

(...)

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

提前致谢。

3 个答案:

答案 0 :(得分:4)

这里必须准确无误:

  • get()操作的结果应该是原子的,因为"进一步"任何原子类的保证,也保证可见"可见"查看同一个对象的其他线程(所有** set *方法都是 atomic 的意义上的原子,因此不可能get()某事那是"半套")
  • 而!操作以任何方式受到保护

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

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

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

理论上可能

  • 线程A"得到"假
  • 主题B"设置"真
  • 线程A计算计算! false - >真

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

  • 主题A" getNot" false - >真
  • 主题B"设置"真

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

答案 1 :(得分:3)

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

要使用原子进行排除,通常需要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更差的性能,因为该操作系统通常会“暂停”等待线程并执行其他任务。 但是,在争用率很低的情况下(即很少或不需要等待),自旋锁可以表现出更好的性能。

专业提示:在实践中,最好将condition.set(false) in a最终阻止:

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

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

答案 2 :(得分:0)

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

atomic将是一个与读写内容相关的概念,而你的问题并未提及类似内容。

如果要以原子方式读写(或写入和读取),AtomicBoolean上还有其他方法(如getAndSet或compareAndSet)。从您的问题看,您似乎正在寻找与此更相关的内容(无法从您的问题详细信息中确定)。

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