返回
直击 CAS 的核心魅力:揭秘它为何能够代替 synchronized
Android
2023-12-30 20:40:34
CAS 与 synchronized:并发编程中的两个关键玩家
在多线程编程的世界里,协调多个线程的访问和修改共享资源至关重要。为了确保数据的完整性和程序的正确性,我们需要可靠的同步机制。在 Java 中,CAS(Compare-and-swap)和 synchronized 是两个最常用的选择。
CAS:无锁并发原语
CAS(Compare-and-swap)是一种无锁并发原语,这意味着它不需要获取和释放锁来完成操作。它背后的思想是,在执行更新之前,先比较内存中变量的当前值与预期值是否一致。如果一致,则执行更新;如果不一致,则放弃更新。
步骤详解:
- 读取变量的当前值。
- 比较变量的当前值与预期值是否一致。
- 如果一致,则执行更新操作;如果不一致,则放弃更新。
示例代码:
public class CASDemo {
private int counter = 0;
public void incrementCounter() {
int expectedValue = counter;
while (!CAS(expectedValue, expectedValue + 1)) {
// CAS 操作失败,重试
expectedValue = counter;
}
}
private boolean CAS(int expectedValue, int newValue) {
return AtomicInteger.compareAndSet(counter, expectedValue, newValue);
}
}
synchronized:基于锁的同步机制
synchronized 是 Java 中内置的锁机制,它通过获取和释放锁来保证线程间的同步。当一个线程获取到一个对象的锁之后,其他线程在访问该对象时必须等待,直到该线程释放锁。
实现方式:
- 内置锁: 使用 synchronized 修饰方法或代码块,可以在方法或代码块执行期间获取对象的锁。
- 显式锁: 使用 ReentrantLock 等显式锁对象,可以在代码中手动获取和释放锁。
示例代码:
public class SynchronizedDemo {
private int counter = 0;
public synchronized void incrementCounter() {
counter++;
}
}
CAS 与 synchronized 的比较
特性 | CAS | synchronized |
---|---|---|
原理 | 无锁并发原语 | 基于锁的同步机制 |
性能 | 高性能 | 低性能 |
适用场景 | 竞争不激烈的场景 | 竞争激烈的场景 |
可重入性 | 不可重入 | 可重入 |
公平性 | 不公平 | 公平 |
为什么 CAS 可以替代 synchronized?
在某些场景下,CAS 可以代替 synchronized,主要原因在于其高性能 。由于 CAS 是无锁并发原语,它不需要获取和释放锁,因此开销很小。而 synchronized 需要获取和释放锁,开销较大。
常见问题解答
-
CAS 是否适用于所有情况?
- 不,CAS 适用于竞争不激烈的场景。在竞争激烈的场景下,它可能会导致自旋,降低性能。
-
synchronized 是否会导致死锁?
- 是的,synchronized 可能导致死锁,尤其是在多个线程相互持有对方的锁的情况下。
-
CAS 如何避免死锁?
- CAS 是无锁的,它通过比较预期值和当前值来更新变量,避免了死锁的发生。
-
何时应该使用 CAS?
- 在竞争不激烈且需要高性能的场景下,例如计数器、标志位等。
-
何时应该使用 synchronized?
- 在竞争激烈且需要可重入性和公平性的场景下,例如共享资源的访问等。
总结
CAS 和 synchronized 都是 Java 并发编程中重要的同步机制。CAS 是无锁并发原语,具有高性能和避免死锁的优点,但适用于竞争不激烈的场景。synchronized 是基于锁的同步机制,具有可重入性和公平性的优点,但性能较低,适用于竞争激烈的场景。在实际应用中,需要根据具体场景选择合适的锁机制。