• java AQS源码分析


    java常用的锁ReentrantLock主要利用AQS框架实现,ReentrantLock主要结构如图

    其主要利用的是内部类Sync来实现加锁解锁操作,而Sync继承了AbstractQueuedSynchronizer累,大部分操作由AbstractQueuedSynchronizer来完成

    ReentrantLock常用方法为加锁lock()与解锁unlock(), 加锁利用了AbstractQueuedSynchronizer的acquire方法,AbstractQueuedSynchronizer本身没有实现tryAcquire方法,并且抛出一个异常强制子类必须实现才能成为一个锁类,ReentrantLock通过内部类NonfairSync与FairSync提供了两个不同的tryAcquire实现来构造公平锁或者与公平锁,下面先介绍公平锁的原理

     1 protected boolean tryAcquire(int acquires) {
     2             final Thread current = Thread.currentThread();
     3             int c = getState();
     4             if (c == 0) {
     5                 if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
     6                     setExclusiveOwnerThread(current);
     7                     return true;
     8                 }
     9             } else if (current == getExclusiveOwnerThread()) {
    10                 int nextc = c + acquires;
    11                 if (nextc < 0)
    12                     throw new Error("Maximum lock count exceeded");
    13                 setState(nextc);
    14                 return true;
    15             }
    16             return false;
    17         }
    1 public final void acquire(int arg) {
    2         if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
    3             selfInterrupt();
    4     }

    该方法先调用tryAcquire来快速尝试获取锁,若失败则先调用addWaiter方法来构造一个同步节点,通过死循环+cas方式将此节点加到同步队列尾部,然后调用 acquireQueued来循环获取同步状态,获取到了才推出,因为只要当前节点是头节点时才能拿到状态,所以该过程类似于接力棒,从头结点开始往后一个个获取到同步状态

     1 private Node addWaiter(Node mode) {
     2         Node node = new Node(Thread.currentThread(), mode);
     3         // Try the fast path of enq; backup to full enq on failure
     4         Node pred = tail;
     5         if (pred != null) {
     6             node.prev = pred;
     7             if (compareAndSetTail(pred, node)) {
     8                 pred.next = node;
     9                 return node;
    10             }
    11         }
    12         enq(node);
    13         return node;
    14     }
    15 private Node enq(final Node node) {
    16         for (;;) {
    17             Node t = tail;
    18             if (t == null) { // Must initialize
    19                 if (compareAndSetHead(new Node()))
    20                     tail = head;
    21             } else {
    22                 node.prev = t;
    23                 if (compareAndSetTail(t, node)) {
    24                     t.next = node;
    25                     return t;
    26                 }
    27             }
    28         }
    29     }
     1 final boolean acquireQueued(final Node node, int arg) {
     2         boolean failed = true;
     3         try {
     4             boolean interrupted = false;
     5             for (;;) {
     6                 final Node p = node.predecessor();
     7                 if (p == head && tryAcquire(arg)) {
     8                     setHead(node);
     9                     p.next = null; // help GC
    10                     failed = false;
    11                     return interrupted;
    12                 }
    13                 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
    14                     interrupted = true;
    15             }
    16         } finally {
    17             if (failed)
    18                 cancelAcquire(node);
    19         }
    20     }

    获取同步状态的节点释放是调用release方法,由此实现了加锁解锁操作,并且按照线程请求顺序依次进行

    1 public final boolean release(int arg) {
    2         if (tryRelease(arg)) {
    3             Node h = head;
    4             if (h != null && h.waitStatus != 0)
    5                 unparkSuccessor(h);//该节点释放同步状态,并唤醒下一个节点
    6             return true;
    7         }
    8         return false;
    9     }
  • 相关阅读:
    消息机制
    窗口!窗口!- Windows程序设计(SDK)003
    内联函数的作用
    结构体变量用 . 结构体指针用-> 的原因
    &a和a的区别
    分布电容
    介电常数
    天线
    封装的思想
    关于中断标志位
  • 原文地址:https://www.cnblogs.com/shaozhen/p/11271906.html
Copyright © 2020-2023  润新知