当更新的目标是一个字时,可以采用比使用锁更有效的方法来更新内存。这些替代方法是基于现代处理器中实现的原子或互锁指令。这些通常被称为CAS(Compare And Swap)操作,例如x86上的 "lock cmpxchg"。CAS操作是一种特殊的机器码指令,它允许内存中的一个字被有条件地设置为一个原子操作。对于 "增加一个计数器的实验",每个线程可以在一个循环中读取计数器,然后尝试将其原子化地设置为新的增加值。新旧值作为参数提供给这条指令。如果当操作被执行时,计数器的值与提供的预期值一致,那么计数器就会被更新为新的值。另一方面,如果该值不符合预期,CAS操作将失败。这时,试图执行改变的线程就会重试,重新读取计数器的增量,以此类推,直到改变成功。这种CAS方法比锁的效率高得多,因为它不需要向内核切换上下文来进行仲裁。然而,CAS操作并不是没有成本的。处理器必须锁定其指令流水线以确保原子性,并采用内存屏障来使其他线程看到这些变化。在Java中,通过使用java.util.concurrent.Atomic*类,可以进行CAS操作。
如果程序的关键部分比一个计数器的简单增量更复杂,可能需要一个复杂的状态机,使用多个CAS操作来协调争夺。使用锁来开发并发程序是很困难的;使用CAS操作和内存屏障来开发无锁算法要复杂很多倍,而且很难证明它们是正确的。
理想的算法是只有一个线程拥有对单一资源的所有写入,其他线程读取结果的算法。在多处理器环境中读取结果需要内存屏障,以使在其他处理器上运行的线程看到这些变化。
A more efficient alternative to the use of locks can be employed for updating memory when the target of the update is a single word. These alternatives are based upon the atomic, or interlocked, instructions implemented in modern processors. These are commonly known as CAS (Compare And Swap) operations, e.g. “lock cmpxchg” on x86. A CAS operation is a special machine-code instruction that allows a word in memory to be conditionally set as an atomic operation. For the “increment a counter experiment” each thread can spin in a loop reading the counter then try to atomically set it to its new incremented value. The old and new values are provided as parameters to this instruction. If, when the operation is executed, the value of the counter matches the supplied expected value, the counter is updated with the new value. If, on the other hand, the value is not as expected, the CAS operation will fail. It is then up to the thread attempting to perform the change to retry, re-reading the counter incrementing from that value and so on until the change succeeds. This CAS approach is significantly more efficient than locks because it does not require a context switch to the kernel for arbitration. However CAS operations are not free of cost. The processor must lock its instruction pipeline to ensure atomicity and employ a memory barrier to make the changes visible to other threads. CAS operations are available in Java by using the java.util.concurrent.Atomic* classes.
If the critical section of the program is more complex than a simple increment of a counter it may take a complex state machine using multiple CAS operations to orchestrate the contention. Developing concurrent programs using locks is difficult; developing lock-free algorithms using CAS operations and memory barriers is many times more complex and it is very difficult to prove that they are correct.
The ideal algorithm would be one with only a single thread owning all writes to a single resource with other threads reading the results. To read the results in a multi-processor environment requires memory barriers to make the changes visible to threads running on other processors.