【25】比较并交换


比较并交换,是一个并发算法中常用的技术。 基本上,比较并交换就是将变量的预期值与一个具体值惊醒比较,如果具体值等于预期值,则拿一个新的值与变量交换,这样变量就更新成新的值了。 比较并交换听起来有些复杂,但实际上并不复杂。

适用什么场景

在程序中并发算法会有一个非常常见的模式,称之为:“根据某个状态值来决定如何操作”。("检查-然后-动作") 如下面这个例子:

class MyLock {

    private boolean locked = false;

    public boolean lock() {
        if(!locked) {
            locked = true;
            return true;
        }
        return false;
    }
}

上面这段代码,在多线程中会有问题,这里的并发问题,我们暂时忽略。

lock()方法,首先检查了locked变量是否等于false(检查),如果相等则设置lockedtrue(动作)

如果同一个MyLock实例,被多线程访问,那lock()并不能正常工作。 如果线程A检查了locked的值为false,同一时间,线程B也检查lockedfalse。(或者在线程A更新locked之前) 这样就会导致并发问题,线程A和B都可以看到lockedfalse,然后都会基于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的原子指令来优化。这样比手工代码的性能会高出很多!!!

转载于:https://my.oschina.net/roccn/blog/1610740

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值