AbstractQueuedSynchronizer详解(二)同步器 与 ReentrantLock源码详细分析

 

上一篇我们讲了AbstractQueuedSynchronizer(一)的大致流程:

 AbstractQueuedSynchronizer详解(一)同步器分析

 

现在来看一下ReentrantLock与他相关的详细源码分析:

 

目录

1、同步器类属性字段:       

2、同步队列Node对象属性

3、获取ReentrantLock独占非公平锁

(1)、ReentrantLock 类中的lock方法

(2)、非公平锁的lock()方法

(3)、Sync内部类的lock()方法

(4)、acquire(1)方法抢占锁

(5)、Sync内部类nonfairTryAcquire方法

(6)、acquire方法结果

(7)、addWaiter方法

(8)、addWaiter()方法执行完毕

(9)、 shouldParkAfterFailedAcquire()方法:

(10)、如果挂起失败, 调用parkAndCheckInterrupt()方法

(11)、看一下Thread.interrupted()方法

(12)、回到主方法acquire()查看:

(13)、获取锁方法总结

4、获取ReentrantLock独占公平锁

(1)、客户端使用ReentrantLock:

(2)、调用FairSync公平锁内部类中的lock方法

(3)、FairSync实现的tryAcquire()

(4)、NoFairSync内部类hasQueuedPredecessors()

5、tryLock()方法,尝试获取锁

(1)、客户端代码

6、释放锁

(1)、unlock()方法

(2)、父类AQS中release()方法:

(3)、子类Sync类中tryRelease()方法

(4)、 unparkSuccessor()唤醒方法


 

AbstractQueuedSynchronizer的实现,建议结合他的实现类来一起看,这里我们先选择了ReentrantLock可重入独占锁来一起分析:

1、同步器类属性字段:       

 

//同步队列的头节点
private transient volatile Node head;

//同步队列的尾节点
private transient volatile Node tail;

 //同步状态
private volatile int state;

//如果超时时间小于此阈值,不阻塞线程,让其自旋,在doAcquireNanos、//doAcquireSharedNanos、awaitNanos、await(long time, TimeUnit unit)
//方法使用到
static final long spinForTimeoutThreshold = 1000L;

//获取UnSafe使用
private static final Unsafe unsafe = Unsafe.getUnsafe();

//属性state的相对偏移量,相对AbstractQueuedSynchronizer实例的起始
//内存位置的相对偏移量,定义成静态的原因是,属性的相对实例的偏移量都是//相等的
private static final long stateOffset;

private static final long headOffset;
private static final long tailOffset;
private static final long waitStatusOffset;

//内部类Node实例的属性next的相对偏移量
private static final long nextOffset;

static {
    try {
        stateOffset = unsafe.objectFieldOffset
        //使用UnSafe实例获取AbstractQueuedSynchronizer类的属性
	//state的相对偏移量(AbstractQueuedSynchronizer.class.getDeclaredField("state"));
        headOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
        tailOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
        waitStatusOffset = unsafe.objectFieldOffset
            (Node.class.getDeclaredField("waitStatus"));
        nextOffset = unsafe.objectFieldOffset
            (Node.class.getDeclaredField("next"));

    } catch (Exception ex) { throw new Error(ex); }
}

 

2、同步队列Node对象属性

我们操作的队列,都是基于Node对象的,先来看一下Node对象属性值:

下面来看Node对象的属性:

static final class Node {
    //当前节点是获取共享锁的标记 
    static final Node SHARED = new Node();
    //当前节点是获取独占锁的标记
    static final Node EXCLUSIVE = null;

    //属性waitStatus的值,标志节点对应的线程被取消
    static final int CANCELLED =  1;

    //属性waitStatus的值,标志当前节点的next节点的线程(即队列中    
    //当前节点的下一个节点)需要被阻塞,当前节点的后继节点已经 (或即将)
    //被阻塞(通过park) , 所以当 当前节点释放或则被取消时候 ,一定要
    //unpark它的后继节点。为了避免竞争,获取方法一定要首先设置node
    //为signal,然后再次重新调用获取方法,如果失败,则阻塞

    static final int SIGNAL    = -1;

    //属性waitStatus的值,标志当前节点在Condition条件下等待阻塞,  
    //在Condition实例的await系列方法中使用,新建一个waitStatus的值
    //为CONDITION的节点Node,将其加入到Condition中的条件队列中,
    //表示当前节点正在条件队列(AQS下的ConditionObject里也维护了个
    //队列)中,在从conditionObject队列转移到同步队列前,它不会在同步
    //队列(AQS下的队列)中被使用。当成功转移后,该节点的状态值将由
    //CONDITION设置为0 

    static final int CONDITION = -2;

    //属性waitStatus的值,标志着下一个acquireShared方法线程应该被允
    //许,在获取共享锁

    static final int PROPAGATE = -3;

    ///标记着当前节点的状态,默认状态是0,小于0的状态值都是有特殊作
    //用,大于0的状态值表示已取消

    volatile int waitStatus;

    //使用prev和next实现同步队列,即双向链表,当前节点的前驱节点
    volatile Node prev;

    //当前节点的下一节点指向当前节点的后继节点,在当前节点释放时候会唤  
    //醒后继节点。该后继节点也是在入队时候被分配的。当前驱节点被取消时
    //候,会重新调整链表的节点链接指向关系。如:前驱节点的前驱节点指向
    //当前节点。且把前驱节点设置为null。节点入队操作过程完成前,入队操
    //作并还未设置前驱节点的后继节点。所以会看到前驱节点的后继节点为
    //null,但是这并不意味着前驱节点就是队列的尾节点!如果后继节点为null,
    //我们可以通过从尾节点向前扫描来做双重检测。一个被取消的节点的后继
    //节点被设置为自身。即node.next=node。这样设置会帮助
    //isOnSyncQueue的执行效率更高(即执行时间更短。注意该方法的if 
    //(node.next != null)) 

     volatile Node next;

    //当前节点对应的线程
    volatile Thread thread;

    //有两种作用:1、表示下一个在Condition条件上等待的节点,调用
    //Condition中await和signal方法,当前节点的线程是拥有独占锁的线
    //程2、表示同步队列中的节点是共享模式还是独占模式
    //ConditionObject链表的后继节点或者代表共享模式的节点SHARED。
    //Condition条件队列:因为Condition队列只能在独占模式下被能被访问。 
    //我们只需要简单的使用链表队列来链接正在等待条件的节点。再然后它们
    //会被转移到同步队列(AQS队列)再次重新获取。由于条件队列只能在
    //独占模式下使用,所以我们要表示共享模式的节点的话只要使用特殊值
    //SHARED来标明即可。

    Node nextWaiter;

    //判断当前节点是不是共享模式
    final boolean isShared() {
        return nextWaiter == SHARED;
    }

    //获取当前节点的前驱节点,如果为null,则抛出空指针异常
    final Node predecessor() throws NullPointerException {
        Node p = prev;
        if (p == null)
            throw new NullPointerException();
    //返回当前节点的前驱节点
        else
            return p;
    }
    //在创建链表头head,或者创建节点共享锁标记属性SHARED值
    Node() {        }

    //在addWaiter方法中使用    
    Node(Thread thread, Node mode) {  
    //当前节点的模式,是属于共享模式,还是独占模式   
    this.nextWaiter = mode;
	//将传入进来的线程赋值给节点属性thread
        this.thread = thread;
    }

    //在Condition条件中使用
    Node(Thread thread, int waitStatus) { // Used by Condition
	//将传入节点的状态值赋值给节点属性waitStatus
        this.waitStatus = waitStatus;
	//将传入进来的线程赋值给节点属性thread
        this.thread = thread;
    }
}

3、获取ReentrantLock独占非公平锁

(1)、ReentrantLock 类中的lock方法

/**
 * Acquires the lock.
 *
 * <p>Acquires the lock if it is not held by another thread and returns
 * immediately, setting the lock hold count to one.
 *
 * <p>If the current thread already holds the lock then the hold
 * count is incremented by one and the method returns immediately.
 *
 * <p>If the lock is held by another thread then the
 * current thread becomes disabled for thread scheduling
 * purposes and lies dormant until the lock has been acquired,
 * at which time the lock hold count is set to one.
 

*获取锁。
*
* 如果锁没有被另一个线程持有并且返回,则获取锁
* 立即将锁计数器count设置为1。
*
* 如果当前线程已经保持锁定,则锁计数器
* count加1,方法立即返回。(支持重入锁)
*
* 如果锁由另一个线程持有,那么
* 当前线程会被线程调度置于休眠状态,
* 直到获得锁定为止,
* 此时锁计数器count保持设置为1。
* 调用后一直阻塞到获得锁
*/
    public void lock() {
        sync.lock();
    }

(2)、非公平锁的lock()方法

在客户端代码中调用ReentrantLock类的lock()获取锁

 

//默认非公平锁

//因为非公平性能更好,代码逻辑判断少一些;

Lock lock = new ReentrantLock();
lock.lock();

 

进入到ReentrantLock中,发现是调用sync内部类的lock()方法;

public void lock() {
    sync.lock();
}

 

(3)、Sync内部类的lock()方法

abstract void lock();

 

lock方法实现主要在他的子类NonfairSync和FairSync中

因为这里是非公平锁,所以是调用NonfairSync类的非公平抢占锁方法

final void lock() {
    if (compareAndSetState(0, 1))

        //成功抢到锁,设置当前线程独占
        setExclusiveOwnerThread(Thread.currentThread());
    else
        //设置状态失败,开始抢占锁
        acquire(1);       
}

 

(4)、acquire(1)方法抢占锁

这里调用了父类AbstractQueuedSynchronizer的acquire(1)方法来继续抢占锁

public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

 

首先看if条件中调用的第一个方法,tryAcquire();

父类中的方法tryAcquire()实现没有具体实现,只提供了一个模板方法

protected boolean tryAcquire(int arg) {
    throw new UnsupportedOperationException();
}

 

那就是调用子类中的具体实现

protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}

 

(5)、Sync内部类nonfairTryAcquire方法

这里继续调用了Sync内部类nonfairTryAcquire方法

/**
 * Performs non-fair tryLock.  tryAcquire is implemented in
 * subclasses, but both need nonfair try for trylock method.
 */
final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
	//状态值为0的时候,表示未上锁
    if (c == 0) {
		//cas抢占锁,如果抢占成功,设置独占锁
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    //上述cas抢占失败,或者c状态值不为0的时候
    //判断是否为当前线程,如果为当前线程,那么可重入锁+1
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    //否则抢占锁失败,返回false
    return false;
}

(6)、acquire方法结果

到这里,我们只完成了父类中if条件中的第一个tryAcquire方法:如果tryAcquire抢占成功返回true,!true = false,if第一个条件为false,终止执行;


public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

(7)、addWaiter方法

如果tryAcquire抢占失败,那么就要入队列排队等待了;执行acquireQueued()方法,里面还有一个addWaiter ()方法:


private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    // Try the fast path of enq; backup to full enq on failure
    //这里快速调用一次入队尾方法,只能插入一个节点,后面的节点都要
    //进入 enq()方法插入;
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    enq(node);
    return node;
}

//我们再来看enq()方法

private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        if (t == null) { // Must initialize
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            node.prev = t;
            // 基于这一步的CAS,如果在插入中,t即tail发生了变化,
            //被其他节点先插入到队尾,那么又重试,
            //直到所有排队节点线程都插入进去才终止循环
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}

(8)、addWaiter()方法执行完毕

经过上面的操作,我们申请获取锁的线程已经成功加入了等待队列,addWaiter()方法执行完毕;

那么节点现在要做的就是挂起当前线程,等待被唤醒;就是下面的 acquireQueued()方法,上述addWaiter()方法执行返回的节点,当做

acquireQueued()的节点参数;


/**
 * Acquires in exclusive uninterruptible mode for thread already in
 * queue. Used by condition wait methods as well as acquire.
 *
 * @param node the node
 * @param arg the acquire argument
 * @return {@code true} if interrupted while waiting
 */

//入队的时候,什么时候停止入队,什么时候把线程挂起

final boolean acquireQueued(final Node node, int arg) {
// failed 判断此方法操作是否失败
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
        	// 获取前驱节点p,如果p是头结点,那么抢占一次锁
        	//为什么前驱节点是头结点了,还抢占锁呢?
        	//如果有非公平锁进来,会抢占锁;
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
            	// 如果抢占锁成功,则把当前节点设置为头结点
                setHead(node);
                p.next = null; // help GC
               //这里抢占成功以后,把failed标记false, 
               //方法返回false,这样上一级就不需要调用线程中断方法()
               //返回false,表示不是被打断failed = false;
               //可以回到调用它的主方法acquire(int arg)中再去查看
            	return  interrupted;
            }
            // 如果节点线程成功挂起,并且检测到中断,interrupted = true
            // 如果成功挂起,没检测到中断,interrupted = false,不中断
            // 如果挂起失败,interrupted = false,不中断
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            //取消获取锁
            cancelAcquire(node);
    }
}

(9)、 shouldParkAfterFailedAcquire()方法:

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    int ws = pred.waitStatus;
	// Node.SIGNAL为-1的时候,表示已经挂起了,等待唤醒状态
    if (ws == Node.SIGNAL)
        /*
         * This node has already set status asking a release
         * to signal it, so it can safely park.
         */
        return true;
    // 大于0,即为1的时候,说明是取消状态
    if (ws > 0) {
        /*
         * Predecessor was cancelled. Skip over predecessors and
         * indicate retry.
         */
        //需要一直找到前面状态不大于0的(不是取消状态的)前驱节点
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        /*
         * waitStatus must be 0 or PROPAGATE.  Indicate that we
         * need a signal, but don't park yet.  Caller will need to
         * retry to make sure it cannot acquire before parking.
         */
        //根据waitStatus的取值限定,这里waitStatus的值
        //只能是0或者//PROPAGATE(-3),那么我们把
        //前置节点的waitStatus设为Node.SIGNAL(-1)
        //然后重新进入调用它的主方法acquireQueued()进行判断
        //如果返回true,那就可以挂起了,
        //就会进入parkAndCheckInterrupt()方法          
        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    }
    return false;
}

(10)、如果挂起失败, 调用parkAndCheckInterrupt()方法


private final boolean parkAndCheckInterrupt() {
    // 实现阻塞当前线程的功能,LockSupport底层
    //添加了blocker对象,该对象主要用于问题排查和系统监控,
    //会打印更多的 dump //堆栈信息,并且不会像Thread中
    // resume()和suspend()那样:
    //如果 resume() 操作出现在 suspend() 之前执行,
    //那么线程将一直处于挂起状态,同时一直占用锁,这就产生了死锁
    LockSupport.park(this);
    //被唤醒之后,返回中断标记,即如果是正常唤醒返回false,
    //如果是中断醒来,就返回true
        
    return Thread.interrupted();
}

(11)、看一下Thread.interrupted()方法


/**
 * Tests whether the current thread has been interrupted.  The
 * <i>interrupted status</i> of the thread is cleared by this method.  In
 * other words, if this method were to be called twice in succession, the
 * second call would return false (unless the current thread were
 * interrupted again, after the first call had cleared its interrupted
 * status and before the second call had examined it).
 *
 * <p>A thread interruption ignored because a thread was not alive
 * at the time of the interrupt will be reflected by this method
 * returning false.
 *
 * @return  <code>true</code> if the current thread has been interrupted;
 *          <code>false</code> otherwise.
 * @see #isInterrupted()
 * @revised 6.0
 */
//返回当前线程是否中断,如果中断返回true;
//此方法会清除线程的中断状态,
//换句话说:如果这个方法连续两次被调用,那么
//第二次调用将返回false(除非当前线程是
//在第一次通话清除其中断状态后,在第二次检查中断之前,
//再次进行了中断)

public static boolean interrupted() {
    return currentThread().isInterrupted(true);
}

(12)、回到主方法acquire()查看:

 

public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

如果先获取锁成功,if第一个条件返回false,!flase =true,后续不执行;

如果先获取锁失败,!flase = true,并且acquireQueued()加入队列成功,当前线程打断selfInterrupt(),让出cpu资源,等待队列唤醒;

如果先获取锁失败,!flase = true,并且acquireQueued()方法返回失败(抢占锁成功则入队失败),则不打断当前线程:


(13)、获取锁方法总结

至此,一个独占非公平锁的获取流程就执行完成了,上述是解析ReentrantLock的lock()方法获取锁的流程;

在客户调用调用ReentrantLock的trylock()方法也是调用Sync内部类的nonfairTryAcquire()方法;

lock()方法:调用后一直阻塞到获得锁,等待唤醒获取锁;

trylock()方法与lock()方法的区别是:尝试是否能获得锁,如果不能获得立即返回;

ReentrantLock的lockInterruptibly()方法:调用后一直阻塞到获得锁但是接受中断信号;

 

4、获取ReentrantLock独占公平锁

(1)、客户端使用ReentrantLock:

Lock lock = new ReentrantLock(true);
lock.lock();

来看构造方法,这里会用公平内部类FairSync:

public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

 

(2)、调用FairSync公平锁内部类中的lock方法

 

final void lock() {
    acquire(1);
}

 

这里的acquire(1)是调用了父类AbstractQueuedSynchronizer的方法

/**
 * Acquires in exclusive mode, ignoring interrupts.  Implemented
 * by invoking at least once {@link #tryAcquire},
 * returning on success.  Otherwise the thread is queued, possibly
 * repeatedly blocking and unblocking, invoking {@link
 * #tryAcquire} until success.  This method can be used
 * to implement method {@link Lock#lock}.
 *
 * @param arg the acquire argument.  This value is conveyed to
 *        {@link #tryAcquire} but is otherwise uninterpreted and
 *        can represent anything you like.
 */
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

(3)、FairSync实现的tryAcquire()

跟NonFairSync类似,tryAcquire()在父类中只是一个模板放,首先是调用子类FairSync实现的tryAcquire() 方法尝试获取锁资源,如果成功则整个acquire()方法执行完毕,即当前线程获得锁资源,可以进入临界区。

我们来看FairSync实现的tryAcquire() 方法,


    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            if (!hasQueuedPredecessors() &&
                compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            int nextc = c + acquires;
            if (nextc < 0)
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }
}

(4)、NoFairSync内部类hasQueuedPredecessors()

与NoFairSync内部类中tryAcquire()方法唯一的不同是,if条件中多了一个 !hasQueuedPredecessors()判断,这个方式是干嘛的呢?


* @return {@code true} if there is a queued thread preceding the
 *         current thread, and {@code false} if the current thread
 *         is at the head of the queue or the queue is empty
 * @since 1.7
 *是否有前继结点
*/
public final boolean hasQueuedPredecessors() {
    // The correctness of this depends on head being initialized
    // before tail and on head.next being accurate if the current
    // thread is first in queue.
    Node t = tail; // Read fields in reverse initialization order
    Node h = head;
    Node s;
	// 头尾节不相等(说明队列不止一个节点);
    // 并且当前线程节点,不等于头结点的下一个节点;
    //因为是头节点持有锁,头结点释放锁以后,会通知它的next节点线程
    //去获得锁;这里判断前任节点是否为头结点的下一个节点,
    //当前节点线程就不去和头结点的next节点线程抢占锁;
    return h != t &&
        ((s = h.next) == null || s.thread != Thread.currentThread());
}

这就是公平的体现,查看释放有前驱节点抢占锁,hasQueuedPredecessors如果返回false,说明没有前驱节点,!false=true,在tryAcquire ()方法中,if的第一个条件为true之后,才会执行下面的抢占锁流程;

获取公平锁的流程,剩下的和前面非公平锁完全一样了。

 

5、tryLock()方法,尝试获取锁

除了调用lock()方法,还有tryLock()方法可以尝试获取锁

 

(1)、客户端代码

Lock lock = new ReentrantLock();
lock.tryLock();

到源码中:


/**
 * Acquires the lock only if it is not held by another thread at the time
 * of invocation.
 *
 * <p>Acquires the lock if it is not held by another thread and
 * returns immediately with the value {@code true}, setting the
 * lock hold count to one. Even when this lock has been set to use a
 * fair ordering policy, a call to {@code tryLock()} <em>will</em>
 * immediately acquire the lock if it is available, whether or not
 * other threads are currently waiting for the lock.
 * This &quot;barging&quot; behavior can be useful in certain
 * circumstances, even though it breaks fairness. If you want to honor
 * the fairness setting for this lock, then use
 * {@link #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) }
 * which is almost equivalent (it also detects interruption).
 *
 * <p>If the current thread already holds this lock then the hold
 * count is incremented by one and the method returns {@code true}.
 *
 * <p>If the lock is held by another thread then this method will return
 * immediately with the value {@code false}.
 *
 * @return {@code true} if the lock was free and was acquired by the
 *         current thread, or the lock was already held by the current
 *         thread; and {@code false} otherwise
 */
//使用公平策略时,调用tryLock()将立即尝试获取锁,
//无论其他线程是否当前正在等待锁。
//这种“闯入”行为在某些情形下会有用,
//尽管他会打破公平策略的公平性,
//如果你想此锁的公平性设置,请使用
//带时间戳的tryLock(long,TimeUnit)方法
public boolean tryLock() {
    return sync.nonfairTryAcquire(1);
}

所以公平锁使用tryLock()会导致不公平;需要使用tryLock(long,TimeUnit);

 

6、释放锁

前面讲了非公平锁与公平锁获取逻辑,下面讲一下释放锁的流程:

释放锁的时候,不区分公平与非公平之分;

(1)、unlock()方法

在客户端调用unlock()方法

Lock lock = new ReentrantLock(true);
lock.lock();
lock.unlock();

 

Lock接口中也定义了lock()方法

void unlock();

实现在ReentrantLock中

public void unlock() {
    sync.release(1);
}

 

(2)、父类AQS中release()方法:

/**
 * Releases in exclusive mode.  Implemented by unblocking one or
 * more threads if {@link #tryRelease} returns true.
 * This method can be used to implement method {@link Lock#unlock}.
 *
 * @param arg the release argument.  This value is conveyed to
 *        {@link #tryRelease} but is otherwise uninterpreted and
 *        can represent anything you like.
 * @return the value returned from {@link #tryRelease}
 */
public final boolean release(int arg) {
    //tryRealease返回true以后,说明重入锁都释放完
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
	//开始唤醒后驱节点
            unparkSuccessor(h);
        return true;
    }
    return false;
}

父类中的tryRealease()也是一个模板方法,显然需要子类去实现
protected boolean tryRelease(int arg) {
    throw new UnsupportedOperationException();
}

(3)、子类Sync类中tryRelease()方法

(在FairSync和NonFairSync中都没有重新此方法,说明公平和非公平锁,都调用的这同一个释放重入锁的方法)

//可重入锁计数器-1,知道计数器=0的时候,把独占线程置空,返回true;


protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

(4)、 unparkSuccessor()唤醒方法


/**
 * Wakes up node's successor, if one exists.
 *
 * @param node the node
 */
private void unparkSuccessor(Node node) {
    /*
     * If status is negative (i.e., possibly needing signal) try
     * to clear in anticipation of signalling.  It is OK if this
     * fails or if status is changed by waiting thread.
     */
    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);

    /*
     * Thread to unpark is held in successor, which is normally
     * just the next node.  But if cancelled or apparently null,
     * traverse backwards from tail to find the actual
     * non-cancelled successor.
     */
    Node s = node.next;
    //下一个节点为空,或者是取消状态的
    if (s == null || s.waitStatus > 0) {
        s = null;
        //直到找到前面为非取消状态的节点,然后执行下面的唤醒unpark
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    if (s != null)
        //直接调用LockSupport里面的唤醒线程方法
        LockSupport.unpark(s.thread);
}

至此,锁的释放已经完成!

下一篇:

AbstractQueuedSynchronizer详解(三)同步器 之 Condition原理分析

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值