前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【AQS我可以讲十分钟】

【AQS我可以讲十分钟】

作者头像
Java廖志伟
发布2022-03-14 10:46:47
1660
发布2022-03-14 10:46:47
举报
文章被收录于专栏:高级开发进阶高级开发进阶

AQS的全称是AbstractQueuedSynchronizer,也就是抽象队列同步器,它是在java.util.concurrent.locks包下的,也就是JUC并发包。java提供了synchronized关键字内置锁,还提供了显示锁,而大部分的显示锁的底层都用到了AQS,比如只有一个线程能执行ReentrantLock独占锁,又比如多个线程可以同时执行共享锁Semaphore、CountDownLatch、ReadWriteLock,CyclicBarrier。AQS使用模板方法模式,使用者继承AbstractQueuedSynchronizer并重写指定的方法,重写的方法就是对于共享资源state的获取和释放,将AQS在自定义同步组件的实现中,调用它的模板方法,这些模板方法会调用使用者重写的方法,这是模板方法模式很经典的一个运用。另外AQS还维护了一个变量volatile int state,代表了加锁的状态,初始状态下,state的值是0。另外还有一个虚拟的双向队列,这个队列是不存在的,它是抽象的概念,存在结点之间的关联关系,它会将请求共享资源的线程,封装成一个Node结点来实现锁的分配。除此之外AQS内部还有一个线程变量,用来记录当前加锁的是哪个线程,初始化状态下,这个变量是null。拿ReentrantLock加锁举例,线程调用ReentrantLock的lock()方法进行加锁,这个加锁的过程,用CAS将state值从0变为1。一旦线程加锁成功了之后,就可以设置当前加锁线程是自己。ReentrantLock通过多次执行lock()加锁和unlock()释放锁,对一个锁加多次,从而实现可重入锁,每次线程可重入加锁一次,判断一下当前加锁线程是不是自己,如果是他自己就可以可重入多次加锁,每次加锁,就是把state的值给累加1。当state=1时代表当前对象锁已经被占用,其他线程来加锁时则会失败,然后再去看加锁线程的变量里面是不是自己之前占用过这把锁,如果不是就说明有其他线程占用了这个锁,失败的线程被放入一个等待队列中,在等待唤醒的时候,经常会使用自旋(while(!cas()))的方式,不停地尝试获取锁,等待已经获得锁的线程,释放锁才能被唤醒。当它释放锁的时候,将AQS内的state变量的值减1,如果state值为0,就彻底释放锁,会将“加锁线程”变量设置为null。这个时候,会从等待队列的队头唤醒其他线程重新尝试加锁,获得锁成功之后,会把“加锁线程”设置为线程自己,同时线程自己就从等待队列中出队。这个就是aqs实现自旋锁,可重入锁,独占锁的底层实现。接着拿CountDownLatch举例,任务分为5个子线程去执行,state也初始化为5。这5个子线程是并行执行的,每个子线程执行完后countDown()一次,state会CAS减1,等到所有子线程都执行完后,state=0,会unpark()主调用线程,然后主调用线程就会从await()函数返回,继续后余动作。

在这里插入图片描述
在这里插入图片描述

整个图片,歇歇眼,文章大多不换行,排版基本都是一块的,一千三百字,口速快的话,十分钟差不多可以讲完,这篇博文主要是针对面试口述的,备战面试。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022/03/11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档