死磕 java同步系列之AQS终篇(面试)
问题
(1)AQS的定位?
(2)AQS的重要组成部分?
(3)AQS运用的设计模式?
(4)AQS的总体流程?
简介
AQS的全称是AbstractQueuedSynchronizer,它的定位是为Java中几乎所有的锁和同步器提供一个基础框架。
在之前的章节中,我们一起学习了ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch的源码,今天我们一起来对AQS做个总结。
状态变量state
AQS中定义了一个状态变量state,它有以下两种使用方法:
(1)互斥锁
当AQS只实现为互斥锁的时候,每次只要原子更新state的值从0变为1成功了就获取了锁,可重入是通过不断把state原子更新加1实现的。
(2)互斥锁 + 共享锁
当AQS需要同时实现为互斥锁+共享锁的时候,低16位存储互斥锁的状态,高16位存储共享锁的状态,主要用于实现读写锁。
互斥锁是一种独占锁,每次只允许一个线程独占,且当一个线程独占时,其它线程将无法再获取互斥锁及共享锁,但是它自己可以获取共享锁。
共享锁同时允许多个线程占有,只要有一个线程占有了共享锁,所有线程(包括自己)都将无法再获取互斥锁,但是可以获取共享锁。
AQS队列
AQS中维护了一个队列,获取锁失败(非tryLock())的线程都将进入这个队列中排队,等待锁释放后唤醒下一个排队的线程(互斥锁模式下)。
Condition队列
AQS中还有另一个非常重要的内部类ConditionObject,它实现了Condition接口,主要用于实现条件锁。
ConditionObject中也维护了一个队列,这个队列主要用于等待条件的成立,当条件成立时,其它线程将signal这个队列中的元素,将其移动到AQS的队列中,等待占有锁的线程释放锁后被唤醒。
Condition典型的运用场景是在BlockingQueue中的实现,当队列为空时,获取元素的线程阻塞在notEmpty条件上,一旦队列中添加了一个元素,将通知notEmpty条件,将其队列中的元素移动到AQS队列中等待被唤醒。
模板方法
AQS这个抽象类把模板方法设计模式运用地炉火纯青,它里面定义了一系列的模板方法,比如下面这些:
// 获取互斥锁
public final void acquire(int arg) {
// tryAcquire(arg)需要子类实现
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// 获取互斥锁可中断
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// tryAcquire(arg)需要子类实现
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
// 获取共享锁
public final void acquireShared(int arg) {
// tryAcquireShared(arg)需要子类实现
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
// 获取共享锁可中断
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// tryAcquireShared(arg)需要子类实现
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
// 释放互斥锁
public final boolean release(int arg) {
// tryRelease(arg)需要子类实现
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
// 释放共享锁
public final boolean releaseShared(int arg) {
// tryReleaseShared(arg)需要子类实现
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
获取锁、释放锁的这些方法基本上都穿插在ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch的源码解析中了,现在看他们是不是舒服多了,如果一开始就看这些源码,难免会很晕。
需要子类实现的方法
上面一起学习了AQS中几个重要的模板方法,下面我们再一起学习下几个需要子类实现的方法:
// 互斥模式下使用:尝试获取锁
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
// 互斥模式下使用:尝试释放锁
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
// 共享模式下使用:尝试获取锁
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
// 共享模式下使用:尝试释放锁
protected boolean tryReleaseShared(int arg) {
throw new UnsupportedOperationException();
}
// 如果当前线程独占着锁,返回true
protected boolean isHeldExclusively() {
throw new UnsupportedOperationException();
}
这几个方法为什么不直接定义成抽象方法呢?
因为子类只要实现这几个方法中的一部分就可以实现一个同步器了,所以不需要定义成抽象方法。
总结
今天我们大概讲了下AQS中几个重要的组成部分,搞明白了这几个结构,AQS对你将没有任何秘密可言,当然面试的时候能把这几个点答清楚,面试官也会眼前一亮的。
(1)状态变量state;
(2)AQS队列;
(3)Condition队列;
(4)模板方法;
(5)需要子类实现的方法;
彩蛋
经过前面的学习,您能简要描述一下AQS获取互斥锁的大体流程吗?
这里彤哥就不作答了,相信学习完前面的内容,答这道题不是个问题了,答不上来的还需要把下面的推荐阅读好好多看几遍^^
推荐阅读
3、 死磕 java同步系列之JMM(Java Memory Model)
8、 死磕 java同步系列之ReentrantLock源码解析(一)——公平锁、非公平锁
9、 死磕 java同步系列之ReentrantLock源码解析(二)——条件锁
10、 死磕 java同步系列之ReentrantLock VS synchronized
11、 死磕 java同步系列之ReentrantReadWriteLock源码解析
13、 死磕 java同步系列之CountDownLatch源码解析
欢迎关注我的公众号“彤哥读源码”,查看更多源码系列文章, 与彤哥一起畅游源码的海洋。

死磕 java同步系列之AQS终篇(面试)的更多相关文章
- 死磕 java同步系列之AQS起篇
问题 (1)AQS是什么? (2)AQS的定位? (3)AQS的实现原理? (4)基于AQS实现自己的锁? 简介 AQS的全称是AbstractQueuedSynchronizer,它的定位是为Jav ...
- 死磕 java同步系列之CyclicBarrier源码解析——有图有真相
问题 (1)CyclicBarrier是什么? (2)CyclicBarrier具有什么特性? (3)CyclicBarrier与CountDownLatch的对比? 简介 CyclicBarrier ...
- 死磕 java同步系列之Phaser源码解析
问题 (1)Phaser是什么? (2)Phaser具有哪些特性? (3)Phaser相对于CyclicBarrier和CountDownLatch的优势? 简介 Phaser,翻译为阶段,它适用于这 ...
- 死磕 java同步系列之zookeeper分布式锁
问题 (1)zookeeper如何实现分布式锁? (2)zookeeper分布式锁有哪些优点? (3)zookeeper分布式锁有哪些缺点? 简介 zooKeeper是一个分布式的,开放源码的分布式应 ...
- 死磕 java同步系列之redis分布式锁进化史
问题 (1)redis如何实现分布式锁? (2)redis分布式锁有哪些优点? (3)redis分布式锁有哪些缺点? (4)redis实现分布式锁有没有现成的轮子可以使用? 简介 Redis(全称:R ...
- 死磕 java同步系列之终结篇
简介 同步系列到此就结束了,本篇文章对同步系列做一个总结. 脑图 下面是关于同步系列的一份脑图,列举了主要的知识点和问题点,看过本系列文章的同学可以根据脑图自行回顾所学的内容,也可以作为面试前的准备. ...
- 死磕 java同步系列之StampedLock源码解析
问题 (1)StampedLock是什么? (2)StampedLock具有什么特性? (3)StampedLock是否支持可重入? (4)StampedLock与ReentrantReadWrite ...
- 死磕 java同步系列之Semaphore源码解析
问题 (1)Semaphore是什么? (2)Semaphore具有哪些特性? (3)Semaphore通常使用在什么场景中? (4)Semaphore的许可次数是否可以动态增减? (5)Semaph ...
- 死磕 java同步系列之ReentrantReadWriteLock源码解析
问题 (1)读写锁是什么? (2)读写锁具有哪些特性? (3)ReentrantReadWriteLock是怎么实现读写锁的? (4)如何使用ReentrantReadWriteLock实现高效安全的 ...
随机推荐
- Java之IO初识(字节流和字符流)
IO概述 生活中,你肯定经历过这样的场景.当你编辑一个文本文件,忘记了 ctrl+s ,可能文件就白白编辑了.当你电脑上插入一个U盘,可以把一个视频,拷贝到你的电脑硬盘里.那么数据都是在哪些设备上的呢 ...
- 3种不走寻常路的黑客攻击泄露&如何保护自己?
数据泄露和黑客攻击现在已经成为我们日常生活中的常见部分,除非您是网络安全专业人员或您的个人数据受到威胁,否则您实际上并不关心是否存在新的漏洞. 正如美国联邦贸易委员会指出的那样,万豪酒店连锁店的超过5 ...
- Web安全测试学习笔记-DVWA-SQL注入-2
接上一篇SQL注入的学习笔记,上一篇我通过报错信息得知后台数据库是MySQL(这个信息非常重要~),然后通过SQL注入拿到了用户表的所有行,其实我们还可以通过MySQL的特性来拿更多的信息. 1. 获 ...
- Xcode 中配置 clang-format 格式化 C++ 代码
Xcode 自带的代码格式化功能(control + I)很有限,其 "格式化" 仅限于设置缩进,代码里面的格式是不会处理的.所以需要借助额外的工具来完成代码的美化. clang- ...
- Android中在fragment中实现点击按钮事件
在fragment不能直接进行点击事件,需要放到oncreatActivity中 具体方法如下: 需要注意的是import android.support.v4.app.Fragment;导入的这个包 ...
- .NETCore C# 中级篇2-6 Json与XML
.NETCoreCSharp 中级篇2-6 本节内容为Json和XML操作 简介 Json和XML文本是计算机网络通信中常见的文本格式,其中Json其实就是JavaScript中的数组与对象,体现了一 ...
- Selenium(一):原理与安装、简单的使用
1. selenium原理 1.1 selenium介绍 Selenium是一个Web应用的自动化框架. 通过它,我们可以写出自动化程序,像人一样在浏览器里操作web界面. 比如点击界面按钮,在文本框 ...
- Docker 镜像与容器
镜像和容器的关系 容器提交 commint 作用: 根据容器生成一个新的镜像 命令格式: docker commit [OPTIONS] CONTAIN ...
- [browser location和history] 简单实现了个路由[转载]
今天看了1下前面写的,好像缺乏交流性,周末再来弄吧 -0- 今天看了browser 的 location 和 history location属性 // //location.hash 性是一个可读可 ...
- 使用vue在开发中的一些小问题--使用vue-cli起的服务器无法在局域网访问
2.使用vue-cli起的服务器无法在局域网访问 这个很简单,在package.json文件中的js启动项配置中增加--host 0.0.0.0 注意是--host而不是-host,此时如果有--op ...