ReentrantLock源码分析--jdk1.8

JDK1.8

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

ReentrantLock概述

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

ReentrantLock源码分析

/**
 * @since 1.5
 * @author Doug Lea
 * 独占锁 --默认使用非公平锁模式
 * 可重入
 * 
 * synchronized锁经过监视器Monitor来实现同步,monitorenter加锁,monitorexit解锁。
 * synchronized是可重如的非公平锁
 * synchronized在jdk1.6进行优化,添加了偏向锁、轻量级锁、重量级锁,关键字之锁的升级(偏向锁->轻量级锁->重量级锁)
 * 偏向锁:当线程访问同步块时,会使用 CAS 将线程 ID 更新到锁对象的 Mark Word 中,若是更新成功则得到偏向锁,而且以后每次进入这个对象锁相关的同步块时都不须要再次获取锁了。
 * 轻量级锁:若是同步对象为无锁状态时,直接尝试CAS更新Mark Word添加锁,若是成功,得到锁,失败升级为重量级锁
 * 重量级锁:是指当锁是轻量级锁时,当自旋的线程自旋了必定的次数后,尚未获取到锁,就会进入阻塞状态,该锁升级为重量级锁,重量级锁会使其余线程阻塞,性能下降。
 * 在使用 CAS 时,若是操做失败,CAS 会自旋再次尝试。因为自旋是须要消耗 CPU 资源的,因此若是长期自旋就白白浪费了 CPU。JDK1.6加入了适应性自旋:若是某个锁自旋不多成功得到,那么下一次就会减小自旋。
 */
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源码分析--jdk1.8

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

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做为惟一指标,公平锁
可以减小“饥饿”发生的几率,等待越久的请求越可以获得优先知足。
相关文章
相关标签/搜索