Concurrent的实现

来源: 深入理解Java内存模型(五)——锁
     java的CAS同时具有 volatile 读和volatile写的内存语义,

     因此Java线程之间的通信现在有了下面四种方式:

线程写volatile变量,随后B线程读这个volatile变量。
线程写volatile变量,随后B线程用CAS更新这个volatile变量。
线程用CAS更新一个volatile变量,随后B线程用CAS更新这个volatile变量。
线程用CAS更新一个volatile变量,随后B线程读这个volatile变量。

 
Java的CAS会使用现代处理器上提供的高效机器级别原子指令,这些原子指令以原子方式对内存执行读-改-写操作,这是在多处理器中实现同步的关键(从本质上来说,能够支持原子性读-改-写指令的计算机器,是顺序计算图灵机的异步等价机器,因此任何现代的多处理器都会去支持某种能对内存执行原子性读-改-写操作的原子指令)。同时,volatile变量的读/写和CAS可以实现线程之间的通信。把这些特性整合在一起,就形成了整个concurrent包得以实现的基石。如果我们仔细分析concurrent包的源代码实现,会发现一个通用化的实现模式:

首先,声明共享变量为volatile;
然后,使用CAS的原子条件更新来实现线程之间的同步;
同时,配合以volatile的读/写和CAS所具有的volatile读和写的内存语义来实现线程之间的通信。

 

        AQS,非阻塞数据结构和原子变量类(java.util.concurrent.atomic包中的类),这些concurrent包中的基础类都是使用这种模式来实现的,而concurrent包中的高层类又是依赖于这些基础类来实现的。从整体来看,concurrent包的实现示意图如下:

由上可知 , CAS 和 volatile 在Java的并发编程中,所起到的巨大作用:

 CAS解决了比较和更新的原子性,volatile保证对于所有的线程都是可见的。

 Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
volatile关键字有两层含义:
1.对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
2.volatile前后的代码不能重排

就拿原子变量类的AtomicInteger来说:

 

/** 
 * Atomically increments by one the current value. 
 * 
 * @return the previous value 
 */  
public final int getAndIncrement() {  
    for (;;) {  
        int current = get();  
        int next = current + 1;  // 可能你会想,到这一步的时候,并没有加锁,那么所有的线程都可以修改啊!但是核心之处就在于下面那个CAS操作,结果会立马可见
        if (compareAndSet(current, next)) //  比如说,线程A , B ,同时到达 next , A ,next = 2 B ,next = 2 , 然后A进CAS ,成功交换,B再进入,但是他会Compare当前值并
            return current;  //不会相等,所以操作会失败 
    }  
}  

猜你喜欢

转载自kainever7.iteye.com/blog/2203719