
【JDK源码分析系列】ReentrantLock 源码分析
发布日期:2021-05-07 20:54:20
浏览次数:25
分类:精选文章
本文共 8273 字,大约阅读时间需要 27 分钟。
【JDK源码分析系列】ReentrantLock 源码分析
【1】内部同步类 -- Sync
/** * 内部类变量 * ReentrantLock 可重入锁的实现实际上是基于内部类 Sync 实现的; */ private final Sync sync; /** * Sync 类继承 AbstractQueuedSynchronizer * 通过实现 AbstractQueuedSynchronizer 中的可重写方法实现可重入锁的功能 * * 静态内部类 : * 1. 可以通过静态内部类的全类名来调用静态内部类的静态属性(外部类名.静态内部类名.属性) * 2. 可以通过静态内部类的全类名来调用静态内部类的静态方法(外部类名.静态内部类名.方法) * 3. 不能通过类静态内部类的全类名来调用内部类的非静态属性和方法 * 4. 可以通过创建内部类实例来调用静态内部类的非静态属性和方法 * * 5. 可以直接调用外部类的静态属性 * 6. 可以直接调用外部类的静态方法 * 7. 无法直接调用外部类的非静态属性 * 8. 无法直接调用外部类的非静态方法 * 9. 可以通过创建外部类实例来调用外部类的非静态属性 * 10.可以通过创建外部类实例来调用外部类的非静态方法 */ abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; /** * 提供抽象方法,方便子类重写,实现加锁的功能 */ abstract void lock(); /** * 非公平的获取锁的方法 * tryAcquire 在子类中实现,实现 tryAcquire 时需要使用到该方法 */ final boolean nonfairTryAcquire(int acquires) { // 获取当前线程 final Thread current = Thread.currentThread(); /** * 获取 state,state 为定义在 AbstractQueuedSynchronizer 类中的字段; * 此处 state 用于记录锁重入的次数 */ int c = getState(); /** * 若 state 为 0,则将 acquires 赋值给 state * 并将当前线程设置为独断式访问权限的拥有者 */ if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } /** * 若 state 不为 0,则表明当前锁已经被获取 * 判断当前线程是否为锁的拥有者,若是则增加锁重入的次数 */ else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } /** * 释放锁方法 * 由于锁支持重入,则释放锁时需要减少锁的同步状态 * 当锁的同步状态减少到0时,即可释放锁,即设置独占式访问的拥有者为 null * 释放锁必须确保只能是锁的拥有者释放锁 */ 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; } /** * 该方法用于判断当前线程是否是锁的拥有者 */ protected final boolean isHeldExclusively() { return getExclusiveOwnerThread() == Thread.currentThread(); } /** * 该方法用于创建同步状态 */ final ConditionObject newCondition() { return new ConditionObject(); } // Methods relayed from outer class // 以下定义的方法将提供给外部类使用 /** * 该方法用于获取拥有锁的线程 */ final Thread getOwner() { return getState() == 0 ? null : getExclusiveOwnerThread(); } /** * 该方法用于获取锁的同步状态 * 即锁重入的次数 */ final int getHoldCount() { return isHeldExclusively() ? getState() : 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 } }
【2】非公平锁的同步类 -- NonfairSync
/** * 非公平锁的同步类 */ static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; /** * 加锁处理 */ final void lock() { /** * CAS 方式设置状态值 * 若比较值为 0,表明尚未有线程获取到同步状态: * 此时尝试将同步状态设置为 1,即尝试抢占同步状态; * * 若比较值非 0,表明当前存在获取同步状态的线程; * 此时尝试将同步状态设置为 1,将会失败; */ if (compareAndSetState(0, 1)) /** * 当成功获取同步状态则将当前线程设置为锁的持有者; */ setExclusiveOwnerThread(Thread.currentThread()); else /** * 当获取同步状态失败,则调用 AbstractQueuedSynchronizer 类中的 * public final void acquire(int arg) 方法,再次尝试获取同步状态, * 若仍然获取同步状态失败则加入同步队列不断自旋等待获取同步状态成功的时机; */ acquire(1); } /** * 该方法为 AbstractQueuedSynchronizer 类中需要重写的方法, * 该方法重写后会结合 AbstractQueuedSynchronizer 类中的模板方法, * 实现基于同步队列的方式获取同步状态的操作; * * 在非公平获取锁的方式中实际调用的是内部类 Sync 中的 * final boolean nonfairTryAcquire(int acquires) 方法; */ protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } }
【3】公平锁的同步类 -- FairSync
/** * 公平锁的同步结构 */ static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; /** * 加锁处理 */ final void lock() { /** * 此处为了保证获取同步状态的公平性,直接调用 AbstractQueuedSynchronizer 类中的 * public final void acquire(int arg) 方法尝试获取同步状态, * 若获取同步状态失败则加入同步队列不断自旋等待获取同步状态成功的时机; * 加入队列可以保证获取锁的顺序性; */ acquire(1); } /** * 该方法为 AbstractQueuedSynchronizer 类中需要重写的方法, * 该方法重写后会结合 AbstractQueuedSynchronizer 类中的模板方法, * 实现基于同步队列的方式获取同步状态的操作; */ protected final boolean tryAcquire(int acquires) { // 获取当前线程; final Thread current = Thread.currentThread(); // 获取同步状态; int c = getState(); /** * 同步状态为 0,表明尚未有线程获取到同步状态; * hasQueuedPredecessors() 方法为 AbstractQueuedSynchronizer 类中的 * public final boolean hasQueuedPredecessors() 方法,用于判断同步队列中 * 是否存在排列在当前线程之前的线程; * * !hasQueuedPredecessors() : 表明只有当当前线程是队列的首节点时, * 才能够尝试获取同步状态, * 这样保证了获取锁的操作的顺序性; * compareAndSetState(0, acquires) : 表明竞争获取同步状态的操作; * 若成功则将当前线程设置为锁的持有者; */ if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } /** * current == getExclusiveOwnerThread() : 表明此锁是被当前线程所拥有; * 此处做重入处理,主要是更新了同步状态; */ 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】提供给外部的方法
/** * 构造方法,默认构造非公平方式获取同步状态; */ public ReentrantLock() { sync = new NonfairSync(); } /** * 构造方法,此方法按照指定的方式获取同步状态; */ public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); } /** * ReentrantLock 类的加锁方法; * 调用内部类 Sync 中的 abstract void lock() 方法, * 该方法会在 Sync 类的子类中重写, * 从而实现公平或非公平方式获取同步状态的操作; */ public void lock() { sync.lock(); } /** * 加锁并能够响应中断; * 实际是调用 AbstractQueuedSynchronizer 类的 * public final void acquireInterruptibly(int arg) 实现的; */ public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } /** * tryLock() : 非公平式获取同步状态的方法; */ public boolean tryLock() { return sync.nonfairTryAcquire(1); } /** * tryLock(long timeout, TimeUnit unit) : 尝试获取锁的方法 * 同时响应中断并由超时限制; */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } /** * 释放锁操作 */ public void unlock() { sync.release(1); }
参考致谢
本博客为博主的学习实践总结,并参考了众多博主的博文,在此表示感谢,博主若有不足之处,请批评指正。 【1】Java并发编程的艺术发表评论
最新留言
感谢大佬
[***.8.128.20]2025年04月16日 21时13分53秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
数据仓库建模方法论
2021-05-09
虚拟机搭建hadoop环境
2021-05-09
DataStax Bulk Loader教程(四)
2021-05-09
.NET应用框架架构设计实践 - 概述
2021-05-09
Rust 内置 trait :PartialEq 和 Eq
2021-05-09
Hibernate(十四)抓取策略
2021-05-09
[菜鸟的设计模式之旅]观察者模式
2021-05-09
Spring-继承JdbcDaoSupport类后简化配置文件内容
2021-05-09
Java基础IO流(一)
2021-05-09
Hibernate入门(四)---------一级缓存
2021-05-09
MySQL事务(学习笔记)
2021-05-09
一个web前端开发者的日常唠叨
2021-05-09
内存分配-slab分配器
2021-05-09
技术写作技巧分享:我是如何从写作小白成长为多平台优秀作者的?
2021-05-09
Jupyter Notebook 暗色自定义主题
2021-05-09
[Python学习笔记]组织文件
2021-05-09
基于Redo Log和Undo Log的MySQL崩溃恢复流程
2021-05-09
从RocketMQ的Broker源码层面验证一下这两个点
2021-05-09
如何正确的在项目中接入微信JS-SDK
2021-05-09
纵览全局的框框——智慧搜索
2021-05-09