AQS 实现的同步框架 构建和维护双向的同步队列
获取锁的方式 是独占还是共享? 能不能获取锁? 获取锁的优先级是公平还是非公平?都是有上层各种同步器实现实现的
这里说的锁都是aqs里面的一个volatile变量 aqs获取操作同步资源的接口 有实现类来定义逻辑
ReentrantLock 重写aqs获取和释放锁的方法 是否公平进入队列修改state同步资源 实现公平和非公平锁 锁作为一种标志 用来控制所有线程的并发行为
CountDownLatch 共享模式获取和释放锁 锁只是作为一种标志 用来唤醒因调用await方法阻塞再队列里面的线程
1:同步资源 即锁的实际表示
volatile int state;
state为0时表示没有线程持有 大于0时表示线程
对外方法
1 双向队列 遵循先进先出原则 (入队和出队时间复杂度都是O(1) 用空间换时间 )
是什么?
储存同步获取资源失败的线程 头结点持有锁 头结点释放锁之后会唤醒后面的节点
Node属性 sync nodes和condition nodes
static final Node SHARED = new Node();//静态标识共享
static final Node EXCLUSIVE = null;//静态标识独占
static final int CANCELLED = 1;//当前节点是取消转态 加入队列后 尝试阻塞线程的过程中 线程获得了锁或者异常 则取消节点
static final int SIGNAL = -1;//节点为SIGNAL 可以被前一个节点唤醒
static final int CONDITION = -2; //表示condition队列中 没有其他用处
static final int PROPAGATE = -3; // 头结点拥有 确共享模式释放锁可持续进行下去 在共享模式释放锁的时候设置头结点
//大于0 状态不可逆 可以直接判断节点的正负来判断节点是否可用 通过 cas修改
volatile int waitStatus;
//本节点检查状态依赖前一个节点 进队时候设置 出队的时候置空方便GC
//如果前一个节点为cancel状态时 总能找到一个非cancel状态的节点 因为头结点不会是cancel状态
//原因如下:队列在进入队列以后 尝试进入阻塞状态并在唤醒之后尝试获取锁
//(acquireQueued|doAcquireInterruptibly|doAcquireNanos|doAcquireShared|doAcquireSharedInterruptibly|doAcquireSharedNanos)
//这些都是节点入队以后的操作 他们的结构大致像下面这样 for循环有两个出口 一个unpark之后获取锁并取代头结点位置取代头结点位置 此时failed为false 不会进入cancelAcquire方法 头结点也就不会设置为cancel状态
//try {
// for (;;) {//两个出口 一个是获得锁 取代头结点位置 二线程抛异常 进入finally方法 }
// } finally {
// if (failed)
// cancelAcquire(node);
// }
volatile Node prev;
volatile Node next;
volatile Thread thread;
//1和内部类ConditionObject 的condition队列公用此节点类 ConditionObject 方便转移内部node节点到外部的fifo队列
//2 或者标识节点的等待状态时共享模式 (不会和condition冲突 condition都是独占模式)
Node nextWaiter;
final boolean isShared() {
return nextWaiter == SHARED;
}
/ /安全获取前节点 省去了判null
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() {
}
// 入fifo队
Node(Thread thread, Node mode) {
this.nextWaiter = mode;
this.thread = thread;
}
//如condition队
Node(Thread thread, int waitStatus) { // Used by Condition
this.waitStatus = waitStatus;
this.thread = thread;
}
CLH变种队列
概念获取不到锁cas入队 关注前一个节点锁状态 然后一直自旋 (aqs 变种 关注前一个节点 但是会阻塞)
前一个节点释放锁只处理第一个节点 即第一个节点接受锁释放的事假 避免惊群现象 zookeeper使用类似的机制