有一种思想流派认为,您应该尽可能节俭地使用锁。也就是说,如果可以避免使用锁,则永远不要使用锁,如果必须使用锁,请锁定最短的时间。这背后的原因源于有时将锁放在第一位的相当大的成本,以及一个线程等待而另一个线程在其所需资源上持有锁定的成本。
很长一段时间以来,CPU指令一直可用,称为比较和设置(或简称CAS),旨在帮助解决这个问题,基本上可以:
if (value == providedValue) {
value = newValue;
return true;
} else {
return false;
}
这些指令可以在机器代码级别执行,并且比创建锁快得多。
想象一下,您希望使用这些指令之一以一种在高并行负载下始终正常工作的方式添加到数字中。显然,您可以将其编码为:1
int old = value;
if ( compareAndSet(old, old+1) ) {
// It worked!
} else {
// Some other thread incremented it before I got there.
}
但是,如果失败了,我们该怎么办呢?你猜对了 - 再试一次!CAS
boolean succeeded = false;
do {
int old = value;
if ( compareAndSet(old, old+1) ) {
// It worked!
succeeded = true;
} else {
// Some other thread incremented it before I got there. Just try again.
}
} while (!succeeded);
在那里你可以看到你观察到的模式。
使用这个和类似的习语,可以使用根本没有锁来实现许多功能甚至一些相当复杂的数据结构(通常称为无锁)。例如,下面是环形缓冲区的无锁实现。