- 原文地址:Compare and Swap
- 作者: Jakob Jenkov
比较并交换,是一个并发算法中常用的技术。 基本上,比较并交换就是将变量的预期值与一个具体值惊醒比较,如果具体值等于预期值,则拿一个新的值与变量交换,这样变量就更新成新的值了。 比较并交换听起来有些复杂,但实际上并不复杂。
适用什么场景
在程序中并发算法会有一个非常常见的模式,称之为:“根据某个状态值来决定如何操作”。("检查-然后-动作") 如下面这个例子:
class MyLock {
private boolean locked = false;
public boolean lock() {
if(!locked) {
locked = true;
return true;
}
return false;
}
}
上面这段代码,在多线程中会有问题,这里的并发问题,我们暂时忽略。
lock()方法,首先检查了locked变量是否等于false(检查),如果相等则设置locked为true(动作)
如果同一个
MyLock实例,被多线程访问,那lock()并不能正常工作。 如果线程A检查了locked的值为false,同一时间,线程B也检查locked为false。(或者在线程A更新locked之前) 这样就会导致并发问题,线程A和B都可以看到locked为false,然后都会基于false做出各自动作。
要让这个代码能在多线程下工作正常,就需要保障“检查-然后-动作”是一个原子操作。 原子操作就是让“检查”和后续的“动作”,在执行时不会被分割成多个步骤,而是一起执行。 任何线程开始执行这个过程就不会被其他线程干扰。 也即是,原子操作同一时间只会被一个线程执行。
下面,通过
synchronized来改造:
class MyLock {
private boolean locked = false;
public synchronized boolean lock() {
if(!locked) {
locked = true;
return true;
}
return false;
}
}
现在
lock()方法是一个synchronized方法,这样也就保障了同一个MyLock实例的lock()方法同一时间只会被一个线程执行。
原子化操作
现代CPU内部已经支持比较并交换的原子化操作指令。 从Java 5 开始,
java.util.concurrent.atomic提供了利用CPU原子化指令的API。
下面就使用原子化操作来改造上例中的
lock()方法。
public static class MyLock {
private AtomicBoolean locked = new AtomicBoolean(false);
public boolean lock() {
return locked.compareAndSet(false, true);
}
}
将原有的boolean类型的变量,改成了
AtomicBoolean类型。AtomicBoolean有一个compareAndSet()方法,通过这个方法,就可以原子化的执行比较并交换的过程。
compareAndSet()方法返回true表示已经交换,返回false则说明没有交换。
利用这套API的最大好处就是,底层可以充分利用CPU的原子指令来优化。这样比手工代码的性能会高出很多!!!
本文介绍了并发编程中常用的比较并交换技术,通过示例详细解释了如何使用该技术解决多线程下的锁竞争问题,并展示了如何利用Java的AtomicBoolean类实现原子化操作。

2079

被折叠的 条评论
为什么被折叠?



