以下演示代码如何线程安全?我们确保是否在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();
}
}
答案 0 :(得分:5)
compareAndSet()
, true
会返回v
,因此值已更新为v + 1
。
在您的第一个版本中,如果两个线程都获得相同的初始值,那么一个将成功(更新到v + 1
)而另一个将失败(因为当前值不再是{ {1}})并使用v
和v + 1
重试。
如果此代码旨在返回唯一键,则第一个版本是正确的,因为在返回v + 2
的{{1}}点,当前值保证为compareAndSet()
(即使仅简述)。如果另一个线程修改了对true
和v + 1
的调用之间的值,则第二个版本可能会因竞争条件而返回重复值。
也就是说,您可能想要调查compareAndSet()
的{{1}}方法,这种方法几乎完全相同,但效率更高(没有明确的循环)。
答案 1 :(得分:2)
定义“工作”。
假设value
最初为零。如果第一个函数被调用100次,它将返回1到100之间的每个数字一次。第二个函数没有这个属性。
两个函数都可以生成在函数返回时过期的值。
哪个更“正确”实际上取决于increment
的预期语义。