java 并发工具包,出自Doug Lea , 提供了jdk 自带的一些并发工具类,例如:Collections.synXXX(), CurrentHashMap。

AbstractQueuedSynchronizer (抽象队列同步器),实现了对INT 共享资源并发的 获取、等待、唤醒;
这个机制是由CLH 队列锁🔐来实现的;即将暂时获取不到锁的线程加入到队列中;
这个AQS实现原理图:

image.png
比sync 灵活,可以自己控制加🔐、解🔐;

AQ对资源的共享方式

1)独占
只有一个线程能执行;

2)共享
多个线程可以同时执行,入CountDownLatch、ReadWriteLock;

注:一般独占、共享实现时仅实现一种即可;

公平锁和非公平锁实现

非公平锁 上来就CAS抢占🔐;
公平锁 会严格按照队列方式进行,🔐被占用就排队;

线程加入等待队列时机

当调用tryAccqure() 方法 获取锁失败以后,会调用addWaiter 将当前线程封装成Node;

入参 mode 表示当前节点的状态,传递的参数是 Node.EXCLUSIVE,表示独占状
态。意味着重入锁用到了 AQS 的独占锁功能

  1. 将当前线程封装成 Node
  2. 当前链表中的 tail 节点是否为空,如果不为空,则通过 cas 操作把当前线程的
    node 添加到 AQS 队列
  3. 如果为空或者 cas 失败,调用 enq 将节点添加到 AQS 队列

addWaiter

  1. private Node addWaiter(Node mode) {
  2. Node node = new Node(Thread.currentThread(), mode); //把当前线程封装为 Node
  3. Node pred = tail; //tail 是 AQS 中表示同比队列队尾的属性,默认是 null
  4. if (pred != null) { //tail 不为空的情况下,说明队列中存在节点
  5. node.prev = pred; //把当前线程的 Node 的 prev 指向 tail
  6. if (compareAndSetTail(pred, node)) { //通过 cas 把 node加入到 AQS 队列,也就是设置为 tail
  7. pred.next = node; //设置成功以后,把原 tail 节点的 next指向当前 node
  8. return node;
  9. }
  10. }
  11. enq(node); //tail=null,把 node 添加到同步队列
  12. return node;
  13. }

enq: 通过自旋的方式将当前节点加入到队列中

  1. private Node enq(final Node node) {
  2. for (;;) {
  3. Node t = tail;
  4. if (t == null) { // Must initialize
  5. if (compareAndSetHead(new Node()))
  6. tail = head;
  7. } else {
  8. node.prev = t;
  9. if (compareAndSetTail(t, node)) {
  10. t.next = node;
  11. return t;
  12. }
  13. }
  14. }
  15. }

经典问题

1) ReentrantLock锁公平与非公平实现、重入原理

2)Lock锁与 sync 区别

参考文章

不可不说的Java“锁”事

关于AQS中的enq方法的理解

从ReentrantLock的实现看AQS的原理及应用