最近在读canal-adpter源码的时候,源码里通过AQS+zookeeper实现了分布式锁。尝试看了一下,看不懂通过搜索锁类继承的父类才发现是AQS所以过来阅读源码。
阅读方式:直接看对应方法 点击<>可以跟代码
什么是AQS
AQS是JUC锁框架中最重要的类,通过它来实现独占锁和共享锁的。比如ReentrantLock、countDownLatch、ReentrantReadWriteLock 都是依靠AQS实现
什么是CAS
参考https://www.cnblogs.com/LQBlog/p/11607351.html#autoid-1-0-0
CLH队列(线程同步队列)
在没有获取到锁的情况下是线程需要阻塞的,需要阻塞的线程是通过CLH队列来存储,CLH并不是直接存储线程,而是通过内部类Node来存储的
内部类Node
static final class Node { // 共享模式的标记 static final Node SHARED = new Node(); // 独占模式的标记 static final Node EXCLUSIVE = null; // waitStatus变量的值,标志着线程被取消 static final int CANCELLED = 1; // waitStatus变量的值,标志着后继线程(即队列中此节点之后的节点)需要被阻塞.(用于独占锁) static final int SIGNAL = -1; // waitStatus变量的值,标志着线程在Condition条件上等待阻塞.(用于Condition的await等待) static final int CONDITION = -2; // waitStatus变量的值,标志着下一个acquireShared方法线程应该被允许。(用于共享锁) static final int PROPAGATE = -3; // 标记着当前节点的状态,默认状态是0, 小于0的状态都是有特殊作用,大于0的状态表示已取消 通过volatile保证了线程的可见性 volatile int waitStatus; // prev和next实现一个双向链表 volatile Node prev; volatile Node next; // 该节点拥有的线程 volatile Thread thread; // 可能有两种作用:1. 表示下一个在Condition条件上等待的节点 // 2. 表示是共享模式或者独占模式,注意第一种情况节点一定是共享模式 Node nextWaiter; // 是不是共享模式 final boolean isShared() { return nextWaiter == SHARED; } // 返回前一个节点prev,如果为null,则抛出NullPointerException异常 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; this.thread = thread; } // 使用在Condition条件中 Node(Thread thread, int waitStatus) { this.waitStatus = waitStatus; this.thread = thread; } }