ReentrantLock源码分析--jdk1.8

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ReentrantLock源码分析--jdk1.8相关的知识,希望对你有一定的参考价值。

JDK1.8

ArrayList源码分析--jdk1.8
LinkedList源码分析--jdk1.8
HashMap源码分析--jdk1.8
AQS源码分析--jdk1.8
ReentrantLock源码分析--jdk1.8

ReentrantLock概述

??1. ReentrantLock是独占锁。
??2. ReentrantLock分为公平模式和非公平模式。
??3. ReentrantLock锁可重入(重新插入)

ReentrantLock源码分析

/**
 * @since 1.5
 * @author Doug Lea
 * 独占锁 --默认使用非公平锁模式
 * 可重入
 */
public class ReentrantLock implements Lock, java.io.Serializable 

    private static final long serialVersionUID = 7373984872572414699L;

    private final Sync sync;

    /**
     * Sync内部类,继承AQS,实现独占锁模式,作为基础内部类
     */
    abstract static class Sync extends AbstractQueuedSynchronizer 
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * 加锁
         */
        abstract void lock();

        /**
         * 判断 reentranLock 状态 是否被锁住(state ?= 0)
         * <p>如果没被锁住尝试 原子性上锁 失败返回false</>
         * <p>如果被锁住 判断是否是当前线程持有锁(重入锁的实现) 如果是 state + 1
         * (信号量  记录该线程持有锁的次数。 该线程每次释放所 信号量 -1。 信号量为零 代表 锁被真正释放)</>
         * <p>else 返回false</p>
         */
        final boolean nonfairTryAcquire(int acquires) 
            final Thread current = Thread.currentThread(); //获取到当前的线程
            int c = getState(); //获取锁的状态
            if (c == 0)  //目前没有人在占有锁 如果锁已被经释放 再次尝试获取锁
                if (compareAndSetState(0, acquires))  //直接尝试把当前只设置成1,如果成功,把owner设置自己,并且退出
                    setExclusiveOwnerThread(current);
                    return true;
                
            
            else if (current == getExclusiveOwnerThread())  // 如果当前线程为锁的拥有者
                int nextc = c + acquires; //这里就是重入锁的概念,如果还是自己,则进行加1操作,因为释放和获取一定要是对等的
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc); // 累加 state 的值  此段代码 实现了重入锁
                return true;
            
            return false; //当前锁被其他线程占用,退出。
        

        /**
         * 释放锁,默认releases传1
         */
        protected final boolean tryRelease(int releases) 
            int c = getState() - releases; //获取当前的锁的状态并且减1,因为要释放锁
            if (Thread.currentThread() != getExclusiveOwnerThread()) //如果当前自己不是锁的持有者,只有自己才能释放锁
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0)  //释放成功
                free = true;
                setExclusiveOwnerThread(null);
            
            setState(c); //重新设置成状态
            return free;
        

        /**
         * 如果当前线程独占着锁,返回true
         */
        protected final boolean isHeldExclusively() 
            // While we must in general read state before owner,
            // we don‘t need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        

        /**
         * 条件队列
         */
        final ConditionObject newCondition() 
            return new ConditionObject();
        

        /**
         * 返回锁的拥有者的线程
         * 当前状态为0返回null,说明在等待中
         * 当前状态不为0返回当前线程
         */
        final Thread getOwner() 
            return getState() == 0 ? null : getExclusiveOwnerThread();
        

        /**
         * 当前线程占着锁返回 state,否则返回0
         */
        final int getHoldCount() 
            return isHeldExclusively() ? getState() : 0;
        

        /**
         * state状态不为0标识上锁,为0表示在等待,不上锁
         */
        final boolean isLocked() 
            return getState() != 0;
        

        /**
         * 反序列化
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException 
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        
    
    /**
     * 构造方法,默认选择非公平锁
     */
    public ReentrantLock() 
        sync = new NonfairSync();
    

    /**
     * 构造方法,true公平锁,false非公平锁
     */
    public ReentrantLock(boolean fair) 
        sync = fair ? new FairSync() : new NonfairSync();
    

ReentrantLock继承和实现分析

技术图片

?? ReentrantLock implements Lock
?? Sync extends AbstractQueuedSynchronizer
?? 1.ReentrantLock实现Lock接口,Lock接口定义了加锁、条件队列、解锁、加锁(中断异常)
?? 2.Sync继承AQS抽象类,实现了独占锁,作为基础内部类

ReentrantLock源码分析

1. FairSync公平锁--内部类

/**
 * 公平锁
 */
static final class FairSync extends Sync 
    private static final long serialVersionUID = -3000897897090466540L;

    final void lock() 
        acquire(1);
    
    /**
     * Fair version of tryAcquire.  Don‘t grant access unless
     * recursive call or no waiters or is first.
     */
    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;
    

2. NonfairSync非公平锁--内部类

/**
 * 非公平锁的同步对象
 */
static final class NonfairSync extends Sync 
    private static final long serialVersionUID = 7316153563782823691L;

    /**
     * Performs lock.  Try immediate barge, backing up to normal
     * acquire on failure.
     * 非公平锁,每次先去获取对象,所以不排队,不公平
     */
    final void lock() 
        //  通过原子操作 改变上锁状态
        if (compareAndSetState(0, 1)) // 变更成功,说明获取锁成功
            setExclusiveOwnerThread(Thread.currentThread()); // 设置持有者为当前线程
        else //变更失败
            acquire(1); //尝试以独占模式获取锁,如果失败加入node节点到队列中
    
    protected final boolean tryAcquire(int acquires) 
        return nonfairTryAcquire(acquires);
    

/**
 * 是否有等待线程
 */
public final boolean hasQueuedThreads() 
    return sync.hasQueuedThreads();

/**
 * 是否有等待线程
 */
public final boolean hasQueuedThreads() 
    return head != tail;

ReentrantLock总结

1)ReentrantLock是可重入的公平/非公平模式的独占锁。
2)ReentrantLock公平锁往往没有非公平锁的效率高,但是,并不是任何场景都是以TPS作为唯一指标,公平锁
能够减少“饥饿”发生的概率,等待越久的请求越能够得到优先满足。

以上是关于ReentrantLock源码分析--jdk1.8的主要内容,如果未能解决你的问题,请参考以下文章

ConcurrentHashMap 源码详细分析(JDK1.8)

jdk1.8 J.U.C并发源码阅读------ReentrantLock源码解析

jdk1.8 J.U.C并发源码阅读------ReentrantLock源码解析

java空间插值,透彻分析源码

AQS源码分析--jdk1.8

深入ArrayList源码分析(JDK1.8)