读书笔记《JAVA并发编程的艺术》 第三章 Java内存模型 3.5 锁的内存语义

3.5 锁的内存语义

3.5.1 锁的释放–获取建立的happens-before关系

锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消息。

3.5.2 锁的释放后和获取的内存语义

  1. 当线程释放锁时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存中。
  2. 当线程获取锁时,JMM会把该线程对应的本地内存置为无效。
    总结:锁释放与volatile写有相同的语义;锁获取与volatile读有相同的内存语义。

3.5.3 锁内存语义的实现

ReentrantLock的源代码

class ReentrantLockExample{
    int a = 0;
    ReentrantLock lock = new ReentrantLock();

    public void writer(){
        lock.lock();              //获取锁
        try {
            a++;
        } finally {
            lock.unlock();       //释放锁
        }
    }   

    public void reader(){
        lock.lock();             //获取锁
        try {
            int i = a;
            .....
        } finally {
            lock.unlock();       //释放锁
        }
    }
}

ReentrantLock的实现依赖于Java同步器框架AbstractQueuedSynchronizer(AQS)。AQS使用一个整型的volatile变量来维护同步状态。

ReentrantLock分为公平锁和非公平锁。

  1. 公平锁和非公平锁释放时,最后都要写一个volatile变量state。
  2. 公平锁获取时,首先会去读volatile变量。
  3. 非公平锁获取时,首先会用CAS更新volaitle变量,这个操作同时具有volatile读和volatile写的内存语义。

从本文对ReentrantLock的分析可以看出,锁释放-获取的内存语义的实现至少有以下两个方式:

  1. 利用volatile变量的写-读所具有的内存语义
  2. 利用CAS所附带的volatile读和volatile写的内存语义

3.5.4 concurrent包的实现

通用化的实现模式:

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

这里写图片描述

猜你喜欢

转载自blog.csdn.net/maohoo/article/details/81213921