Java内存模型学习之锁的内存语义 ReetrantLock的源码分析 Lock释放锁和获取锁的过程(公平锁和非公平锁)

锁的释放和锁的获取:

线程A释放一个锁,实质上是线程A向接下来将要获取这个锁的某个线程发出了(线程A对共享变量所做修改的)消息

线程B获取一个锁,实质上是线程B接收了之前某个线程发出的(在释放这个锁之前对共享变量所做修改的)消息

线程Ashifang释放锁,随后线程B获取这个锁,这个过程实质上是通过线程A通过主内存向线程B发送消息

package juc.lock;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @Description 
 * @Author DJZ-WWS
 * @Date 2019/5/13 14:13
 */
public class ReetrantTest {

int  a=0;
    ReentrantLock  lock=new ReentrantLock();
    public   void  writer(){
        //获取锁
        lock.lock();
        try{
        a++;
        }finally {
            //释放锁
            lock.unlock();
        }
    }
    
    public  void  read(){
        lock.lock();//获取锁
   try {
       int i=a;
       i++;
   }finally {
       lock.unlock();//释放锁
   }
       
;    }
   

}

ReentrantLock的实现依赖于java同步器AbstractQueueSynchronizer(习惯简称为AQS),它使用一个整型的volatile变量来维护同步状态,ReentrantLock分为公平锁,不公平锁,类中有如下源码

Java内存模型学习之锁的内存语义 ReetrantLock的源码分析 Lock释放锁和获取锁的过程(公平锁和非公平锁)

 

 

Java内存模型学习之锁的内存语义 ReetrantLock的源码分析 Lock释放锁和获取锁的过程(公平锁和非公平锁)

这个类图如下:

Java内存模型学习之锁的内存语义 ReetrantLock的源码分析 Lock释放锁和获取锁的过程(公平锁和非公平锁)

使用公平锁时,加锁方法LOck调用轨迹如下:

1.ReentrantLock:lock()

2.FairSync:lock()

2.AbstractQueueSynchronizer.acquire(int arg)。

ReentrantLock这个类中自带lock方法,

Java内存模型学习之锁的内存语义 ReetrantLock的源码分析 Lock释放锁和获取锁的过程(公平锁和非公平锁)

他的内部类使用了Syn内部类的对象调用了自身的lock方法,

Java内存模型学习之锁的内存语义 ReetrantLock的源码分析 Lock释放锁和获取锁的过程(公平锁和非公平锁)

上面的抽象方法有两个实现,一个是公平锁的一个是非公平锁的,这两个锁内部维护着一个lock方法,最终是通过这个最内部的lock方法里面的tryAcquire()方法实现加锁。

Java内存模型学习之锁的内存语义 ReetrantLock的源码分析 Lock释放锁和获取锁的过程(公平锁和非公平锁)

这个方法源码如下:

Java内存模型学习之锁的内存语义 ReetrantLock的源码分析 Lock释放锁和获取锁的过程(公平锁和非公平锁)

从源码中可以看出加锁方法首先读volatile变量state。

Java内存模型学习之锁的内存语义 ReetrantLock的源码分析 Lock释放锁和获取锁的过程(公平锁和非公平锁)

getState()方法如下

Java内存模型学习之锁的内存语义 ReetrantLock的源码分析 Lock释放锁和获取锁的过程(公平锁和非公平锁)

返回结果的state是使用volatile 修饰的,

Java内存模型学习之锁的内存语义 ReetrantLock的源码分析 Lock释放锁和获取锁的过程(公平锁和非公平锁)

以上便是lock实现对公平锁的调用流程

使用公平锁的时,解锁方法unlock()调用轨迹

1.ReentrantLock:unlock()

2.AbstractQueuedSynchronizer:release(int arg)。

3.Sync:tryRelease(int release)

最后一步真正实现释放锁

Java内存模型学习之锁的内存语义 ReetrantLock的源码分析 Lock释放锁和获取锁的过程(公平锁和非公平锁)

        公平锁在释放锁的最后写volatile变量state,在获取锁的时候首先读取这个volatile变量。根据volatile的happen-before规则,释放锁的线程在写volatile之前可见的共享变量,在获取锁的线程读取同一个volatile变量后变得对获取锁的线程可见。

       非公平锁的释放和公平锁完全一样。使用非公平锁加锁的lock的调用轨迹如下:

1>ReentrantLock:lock().

2>NonfairSync:lock();

3>AbstractQueuedSynchronizer:compareAndSetState(int expect,update

第三步的时候实现真正的加锁。

这是NonfairSync内部类的方法调用

Java内存模型学习之锁的内存语义 ReetrantLock的源码分析 Lock释放锁和获取锁的过程(公平锁和非公平锁)

它的底层调用了cas原子操作方法,对于cas前面一片文章已经介绍过,不再赘述

Java内存模型学习之锁的内存语义 ReetrantLock的源码分析 Lock释放锁和获取锁的过程(公平锁和非公平锁)

公平锁和非公平锁释放时最后都要写一个volatile变量state

公平锁和非公平锁释放时,最后都要写一个volatile变量state

公平锁获取时,首先回去读volatile变量

非公平锁获取时,首先会用CAS更新volatile变量,这个操作同时具有volatile读和volatile的内存语义。