AQS简简单单过一遍

前言

回顾前面:java

只有光头才能变强!

原本我是打算在这章节中写Lock的子类实现的,但看到了AQS的这么一个概念,能够说Lock的子类实现都是基于AQS的面试

AQS我在面试题中也见过他的身影,但一直不知道是什么东西。因此本篇我就来说讲AQS这个玩意吧,至少知道它的概念是什么,对吧~算法

那么接下来咱们就开始吧~c#

1、AQS是什么?

首先咱们来普及一下juc是什么:juc其实就是包的缩写(java.util.concurrnt)设计模式

  • 不要被人家唬到了,觉得juc是什么一个牛逼的东西。其实指的是包而已~

咱们能够发现lock包下有三个抽象的类:微信

  • AbstractOwnableSynchronizer
  • AbstractQueuedLongSynchronizer
  • AbstractQueuedSynchronizer

一般地:AbstractQueuedSynchronizer简称为AQS多线程

咱们Lock之类的两个常见的锁都是基于它来实现的:框架

那么咱们来看看AbstractQueuedSynchronizer究竟是什么,看一个类是干什么的最快途径就是看它的顶部注释post

通读了一遍,能够总结出如下比较关键的信息:学习

  • AQS其实就是一个能够给咱们实现锁的框架
  • 内部实现的关键是:先进先出的队列、state状态
  • 定义了内部类ConditionObject
  • 拥有两种线程模式

    • 独占模式
    • 共享模式
  • 在LOCK包中的相关锁(经常使用的有ReentrantLock、 ReadWriteLock)都是基于AQS来构建
  • 通常咱们叫AQS为同步器

2、简单看看AQS

上面也提到了AQS里边最重要的是状态和队列,咱们接下来就看看其源码是怎么样的...

2.1同步状态

使用volatile修饰实现线程可见性:

修改state状态值时使用CAS算法来实现:

2.2先进先出队列

这个队列被称为:CLH队列(三个名字组成),是一个双向队列

看看它队列源码的组成:

static final class Node {
     
        // 共享
        static final Node SHARED = new Node();
      
        // 独占
        static final Node EXCLUSIVE = null;

        // 线程被取消了
        static final int CANCELLED =  1;
  
        // 后继线程须要唤醒
        static final int SIGNAL    = -1;
      
        // 等待condition唤醒
        static final int CONDITION = -2;
      
        // 共享式同步状态获取将会无条件地传播下去(没看懂)
        static final int PROPAGATE = -3;

        
        // 初始为0,状态是上面的几种
        volatile int waitStatus;

        // 前置节点
        volatile Node prev;

        // 后继节点
        volatile Node next;


        volatile Thread thread;

       
        Node nextWaiter;

        final boolean isShared() {
            return nextWaiter == SHARED;
        }

       
        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() {    // Used to establish initial head or SHARED marker
        }

        Node(Thread thread, Node mode) {     // Used by addWaiter
            this.nextWaiter = mode;
            this.thread = thread;
        }

        Node(Thread thread, int waitStatus) { // Used by Condition
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }

2.3acquire方法

获取独占锁的过程就是在acquire定义的,该方法用到了模板设计模式,由子类实现的~

过程:acquire(int)尝试获取资源,若是获取失败,将线程插入等待队列。插入等待队列后,acquire(int)并无放弃获取资源,而是根据前置节点状态状态判断是否应该继续获取资源,若是前置节点是头结点,继续尝试获取资源,若是前置节点是SIGNAL状态,就中断当前线程,不然继续尝试获取资源。直到当前线程被park()或者获取到资源,acquire(int)结束。

来源:

2.4release方法

释放独占锁的过程就是在acquire定义的,该方法也用到了模板设计模式,由子类实现的~

过程:首先调用子类的tryRelease()方法释放锁,而后唤醒后继节点,在唤醒的过程当中,须要判断后继节点是否知足状况,若是后继节点不为且不是做废状态,则唤醒这个后继节点,不然从tail节点向前寻找合适的节点,若是找到,则唤醒.

来源:

3、最后

总结一下AQS究竟是什么吧:

  • juc包中不少可阻塞的类都是基于AQS构建的

    • AQS能够说是一个给予实现同步锁、同步器的一个框架,不少实现类都在它的的基础上构建的
  • 在AQS中实现了对等待队列的默认实现,子类只要重写部分的代码便可实现(大量用到了模板代码)

有兴趣的同窗可去看源码和下面的连接继续学习,我这里就不讲述了。简简单单把AQS过一遍~

明天就看Lock显式锁实现咯~~~

参考资料:

若是文章有错的地方欢迎指正,你们互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同窗,能够 关注微信公众号:Java3y。为了你们方便,刚新建了一下 qq群:742919422,你们也能够去交流交流。谢谢支持了!但愿能多介绍给其余有须要的朋友

文章的目录导航

相关文章
相关标签/搜索