Java并发编程之CAS

前言

 CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术。简单来讲,比较和替换是使用一个指望值和一个变量的当前值进行比较,若是当前变量的值与咱们指望的值相等,就使用一个新值替换当前变量的值。这听起来可能有一点复杂可是实际上你理解以后发现很简单,接下来,让咱们跟深刻的了解一下这项技术。java

CAS的使用场景

在程序和算法中一个常常出现的模式就是“check and act”模式。先检查后操做模式发生在代码中首先检查一个变量的值,而后再基于这个值作一些操做。下面是一个简单的示例:算法

class MyLock {

    private boolean locked = false;

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

上面这段代码,若是用在多线程的程序会出现不少错误,不过如今请忘掉它。多线程

如你所见,lock()方法首先检查locked>成员变量是否等于false,若是等于,就将locked设为true。并发

CAS的ABA问题

若是同个线程访问同一个MyLock实例,上面的lock()将不能保证正常工做。若是一个线程检查locked的值,而后将其设置为false,与此同时,一个线程B也在检查locked的值,又或者,在线程A将locked的值设为false以前。所以,线程A和线程B可能都看到locked的值为false,而后二者都基于这个信息作一些操做。这就是ABA的问题。ide

举个例子,你拿着一个装满钱的手提箱在飞机场,此时过来了一个火辣性感的美女,而后她很暖昧地挑逗着你,并趁你不注意的时候,把用一个如出一辙的手提箱和你那装满钱的箱子调了个包,而后就离开了,你看到你的手提箱还在那,因而就提着手提箱去赶飞机去了。atom

 

为了在一个多线程程序中良好的工做,”check then act” 操做必须是原子的。原子就是说”check“操做和”act“被当作一个原子代码块执行。不存在多个线程同时执行原子块。spa

下面是一个代码示例,把以前的lock()方法用synchronized关键字重构成一个原子块。线程

class MyLock {

    private boolean locked = false;

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

如今lock()方法是同步的,因此,在某一时刻只能有一个线程在同一个MyLock实例上执行它。设计

原子的lock方法其实是一个”compare and swap“的例子同步

CAS用做原子操做

如今CPU内部已经执行原子的CAS操做。Java5以来,你可使用java.util.concurrent.atomic包中的一些原子类来使用CPU中的这些功能。

下面是一个使用AtomicBoolean类实现lock()方法的例子:

public static class MyLock {
    private AtomicBoolean locked = new AtomicBoolean(false);

    public boolean lock() {
        return locked.compareAndSet(false, true);
    }

}

locked变量再也不是boolean类型而是AtomicBoolean。这个类中有一个compareAndSet()方法,它使用一个指望值和AtomicBoolean实例的值比较,和二者相等,则使用一个新值替换原来的值。在这个例子中,它比较locked的值和false,若是locked的值为false,则把修改成true。
若是值被替换了,compareAndSet()返回true,不然,返回false。

使用Java5+提供的CAS特性而不是使用本身实现的的好处是Java5+中内置的CAS特性可让你利用底层的你的程序所运行机器的CPU的CAS特性。这会使还有CAS的代码运行更快

相关文章
相关标签/搜索