java 并发工具包,出自Doug Lea , 提供了jdk 自带的一些并发工具类,例如:Collections.synXXX(), CurrentHashMap。
AbstractQueuedSynchronizer (抽象队列同步器),实现了对INT 共享资源并发的 获取、等待、唤醒;
这个机制是由CLH 队列锁🔐来实现的;即将暂时获取不到锁的线程加入到队列中;
这个AQS实现原理图:
比sync 灵活,可以自己控制加🔐、解🔐;
AQ对资源的共享方式
1)独占
只有一个线程能执行;
2)共享
多个线程可以同时执行,入CountDownLatch、ReadWriteLock;
注:一般独占、共享实现时仅实现一种即可;
公平锁和非公平锁实现
非公平锁 上来就CAS抢占🔐;
公平锁 会严格按照队列方式进行,🔐被占用就排队;
线程加入等待队列时机
当调用tryAccqure() 方法 获取锁失败以后,会调用addWaiter 将当前线程封装成Node;
入参 mode 表示当前节点的状态,传递的参数是 Node.EXCLUSIVE,表示独占状
态。意味着重入锁用到了 AQS 的独占锁功能
- 将当前线程封装成 Node
- 当前链表中的 tail 节点是否为空,如果不为空,则通过 cas 操作把当前线程的
node 添加到 AQS 队列 - 如果为空或者 cas 失败,调用 enq 将节点添加到 AQS 队列
addWaiter
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode); //把当前线程封装为 Node
Node pred = tail; //tail 是 AQS 中表示同比队列队尾的属性,默认是 null
if (pred != null) { //tail 不为空的情况下,说明队列中存在节点
node.prev = pred; //把当前线程的 Node 的 prev 指向 tail
if (compareAndSetTail(pred, node)) { //通过 cas 把 node加入到 AQS 队列,也就是设置为 tail
pred.next = node; //设置成功以后,把原 tail 节点的 next指向当前 node
return node;
}
}
enq(node); //tail=null,把 node 添加到同步队列
return node;
}
enq: 通过自旋的方式将当前节点加入到队列中
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}