使用compareAndSet进行线程安全

时间:2010-12-11 16:38:05

标签: java multithreading

以下演示代码如何线程安全?我们确保是否在CAS指令中修改了值,然后对int进行了增量。 return v + 1;步不会超过整个目的,因为它可以跳过线程的更新。

这里使用原子整数来模仿非阻塞的int计数器。

//Here value is an atomic integer
public int increment() 
{
   int v;
   for(;;) 
   {
      v = value.get();
      if(value.compareAndSet(v, v + 1))
         return v + 1;   
   }
}

代码不应该是这样的:

public int increment() 
{
   int v;
   for(;;) 
   {
      v = value.get();
      if(value.compareAndSet(v, v + 1))
         return value.get();   
   }
}

2 个答案:

答案 0 :(得分:5)

如果当前值等于预期值compareAndSet()

true会返回v,因此值已更新为v + 1

在您的第一个版本中,如果两个线程都获得相同的初始值,那么一个将成功(更新到v + 1)而另一个将失败(因为当前值不再是{ {1}})并使用vv + 1重试。

如果此代码旨在返回唯一键,则第一个版本是正确的,因为在返回v + 2的{​​{1}}点,当前值保证为compareAndSet()(即使仅简述)。如果另一个线程修改了对truev + 1的调用之间的值,则第二个版本可能会因竞争条件而返回重复值。

也就是说,您可能想要调查compareAndSet()的{​​{1}}方法,这种方法几乎完全相同,但效率更高(没有明确的循环)。

答案 1 :(得分:2)

定义“工作”。

假设value最初为零。如果第一个函数被调用100次,它将返回1到100之间的每个数字一次。第二个函数没有这个属性。

两个函数都可以生成在函数返回时过期的值。

哪个更“正确”实际上取决于increment的预期语义。