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
 * 独占锁 --默认使用非公平锁模式
 * 可重入
 * 
 * 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抽象类,实现了独占锁,作为基础内部类

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作为唯一指标,公平锁
能够减少“饥饿”发生的概率,等待越久的请求越能够得到优先满足。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值