资讯专栏INFORMATION COLUMN

AQS简简单单过一遍

EasonTyler / 1535人阅读

摘要:我在面试题中也见过他的身影,但一直不知道是什么东西。直到当前线程被或者获取到资源,结束。简简单单把过一遍明天就看显式锁实现咯参考资料如果文章有错的地方欢迎指正,大家互相交流。为了大家方便,刚新建了一下群,大家也可以去交流交流。

前言

回顾前面:

多线程三分钟就可以入个门了!

Thread源码剖析

多线程基础必要知识点!看了学习多线程事半功倍

Java锁机制了解一下

只有光头才能变强!

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

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

那么接下来我们就开始吧~

一、AQS是什么?

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

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

我们可以发现lock包下有三个抽象的类:

AbstractOwnableSynchronizer

AbstractQueuedLongSynchronizer

AbstractQueuedSynchronizer

通常地:AbstractQueuedSynchronizer简称为AQS

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

那么我们来看看AbstractQueuedSynchronizer到底是什么,看一个类是干什么的最快途径就是看它的顶部注释

通读了一遍,可以总结出以下比较关键的信息:

AQS其实就是一个可以给我们实现锁的框架

内部实现的关键是:先进先出的队列、state状态

定义了内部类ConditionObject

拥有两种线程模式

独占模式

共享模式

在LOCK包中的相关锁(常用的有ReentrantLock、 ReadWriteLock)都是基于AQS来构建

一般我们叫AQS为同步器

二、简单看看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)结束。

来源:

https://blog.csdn.net/panweiwei1994/article/details/78769703

2.4release方法

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

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

来源:

https://zhuanlan.zhihu.com/p/27134110

三、最后

总结一下AQS到底是什么吧:

juc包中很多可阻塞的类都是基于AQS构建的

AQS可以说是一个给予实现同步锁、同步器的一个框架,很多实现类都在它的的基础上构建的

在AQS中实现了对等待队列的默认实现,子类只要重写部分的代码即可实现(大量用到了模板代码)

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

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

参考资料:

https://blog.csdn.net/panweiwei1994/article/details/78769703

https://zhuanlan.zhihu.com/p/27134110

http://cmsblogs.com/?page_id=111

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y。为了大家方便,刚新建了一下qq群:742919422,大家也可以去交流交流。谢谢支持了!希望能多介绍给其他有需要的朋友

文章的目录导航

https://zhongfucheng.bitcron.com/post/shou-ji/wen-zhang-dao-hang

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/69219.html

相关文章

  • Lock锁子类了解一下

    摘要:前言回顾前面多线程三分钟就可以入个门了源码剖析多线程基础必要知识点看了学习多线程事半功倍锁机制了解一下简简单单过一遍只有光头才能变强上一篇已经将锁的基础简单地过了一遍了,因此本篇主要是讲解锁主要的两个子类那么接下来我们就开始吧一锁首先我们来 前言 回顾前面: 多线程三分钟就可以入个门了! Thread源码剖析 多线程基础必要知识点!看了学习多线程事半功倍 Java锁机制了解一下 AQ...

    时飞 评论0 收藏0
  • 线程池你真不来了解一下吗?

    摘要:所以说我们的线程最好是交由线程池来管理,这样可以减少对线程生命周期的管理,一定程度上提高性能。线程池不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。当所有的任务已终止,记录的任务数量为,线程池会变为状态。线程池彻底终止的状态。 前言 只有光头才能变强 回顾前面: ThreadLocal就是这么简单 多线程三分钟就可以入个门了! 多线程基础必要知识点!看了学习多线程事半功倍...

    stdying 评论0 收藏0
  • 多线程之死锁就是这么简单

    摘要:此时线程需要锁才能继续往下执行。但是线程的锁并没有释放,线程的锁也没有释放。 前言 只有光头才能变强 回顾前面: ThreadLocal就是这么简单 多线程三分钟就可以入个门了! 多线程基础必要知识点!看了学习多线程事半功倍 Java锁机制了解一下 AQS简简单单过一遍 Lock锁子类了解一下 线程池你真不来了解一下吗? 本篇主要是讲解死锁,这是我在多线程的最后一篇了。主要将多线程...

    winterdawn 评论0 收藏0
  • Object对象你真理解了吗?

    摘要:无论在中出现什么,都可以认为它是对象除了八大基本数据类型。让当前线程等待某个对象的锁,当然应该通过这个对象来操作了。但是要注意的是方法调用后,被唤醒的线程不会立马获得到锁对象。主要的区别在于在释放同时,释放了对象锁的控制。 前言 五一回家又断更了一个放假时间了~~~ 只有光头才能变强 回顾前面: ThreadLocal就是这么简单 多线程三分钟就可以入个门了! 多线程基础必要知识点!...

    anquan 评论0 收藏0
  • 逐行分析AQS源码(2)——独占锁的释放

    摘要:我们知道,这个函数将返回当前正在执行的线程的中断状态,并清除它。注意,中断对线程来说只是一个建议,一个线程被中断只是其中断状态被设为线程可以选择忽略这个中断,中断一个线程并不会影响线程的执行。 前言 系列文章目录 上一篇文章 我们逐行分析了独占锁的获取操作, 本篇文章我们来看看独占锁的释放。如果前面的锁的获取流程你已经趟过一遍了, 那锁的释放部分就很简单了, 这篇文章我们直接开始看...

    tinna 评论0 收藏0

发表评论

0条评论

EasonTyler

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<