Java并发包源码学习之AQS框架(一)概述
AQS其实就是java.util.concurrent.locks.AbstractQueuedSynchronizer
这个类。 阅读Java的并发包源码你会发现这个类是整个java.util.concurrent
的核心之一,也可以说是阅读整个并发包源码的一个突破口。
比如读ReentrantLock
的源码你会发现其核心是它的一个内部类Sync
:
整个包中很多类的结构都是如此,比如Semaphore
,CountDownLatch
都有一个内部类Sync
,而所有的Sync都是继承自AbstractQueuedSynchronizer
。 所以说想要读懂Java并发包的代码,首先得读懂这个类。
AQS简核心是通过一个共享变量来同步状态,变量的状态由子类去维护,而AQS框架做的是:
- 线程阻塞队列的维护
- 线程阻塞和唤醒
共享变量的修改都是通过Unsafe
类提供的CAS操作完成的。AbstractQueuedSynchronizer
类的主要方法是acquire
和release
,典型的模板方法, 下面这4个方法由子类去实现:
protected boolean tryAcquire(int arg)
protected boolean tryRelease(int arg)
protected int tryAcquireShared(int arg)
protected boolean tryReleaseShared(int arg)
acquire方法用来获取锁,返回true说明线程获取成功继续执行,一旦返回false则线程加入到等待队列中,等待被唤醒,release方法用来释放锁。 一般来说实现的时候这两个方法被封装为lock
和unlock
方法。
下面的SimpleLock
类实现了一个最简单非重入的互斥锁的功能,实际上它就是ThreadPoolExecutor$Worker
的实现(以后的文章会提到这个类)。
class SimpleLock extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -7316320116933187634L; public SimpleLock() { } protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
} protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
} public void lock() {
acquire(1);
} public boolean tryLock() {
return tryAcquire(1);
} public void unlock() {
release(1);
} public boolean isLocked() {
return isHeldExclusively();
}
}
public static void main(String[] args) throws InterruptedException {
final SimpleLock lock = new SimpleLock();
lock.lock(); for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
System.out.println(Thread.currentThread().getId() + " acquired the lock!");
lock.unlock();
}
}).start();
// 简单的让线程按照for循环的顺序阻塞在lock上
Thread.sleep(100);
} System.out.println("main thread unlock!");
lock.unlock();
}
运行上面的测试代码,结果如下:
main thread unlock!
9 acquired the lock!
10 acquired the lock!
11 acquired the lock!
12 acquired the lock!
13 acquired the lock!
14 acquired the lock!
15 acquired the lock!
16 acquired the lock!
17 acquired the lock!
18 acquired the lock!
会发现等待的线程是按照阻塞时的顺序依次获取到锁的。 这是因为AQS是基于一个叫CLH lock queue
的一个变种来实现线程阻塞队列的,我们下一篇文章就来简单了解下CLH lock queue。
后续文章计划如下:
- 《Java并发包源码学习之AQS框架(二)CLH lock queue和自旋锁》
- 《Java并发包源码学习之AQS框架(三)LockSupport》
- 《Java并发包源码学习之AQS框架(四)AbstractQueuedSynchronizer源码分析》
- 《Java并发包源码学习之AQS框架(五)ConditionObject源码分析》
……
- 《Java并发包源码学习之锁(一)概述》
- 《Java并发包源码学习之锁(二)ReentrantLock源码分析》
……
- 《Java并发包源码学习之线程池(一)概述》
- 《Java并发包源码学习之线程池(二)ThreadPoolExecutor源码分析》
……
学习Java并发包源码的初衷是为了搞清之前遇到的一个问题,其实很早之前就打算看这块的源码但一直没看下去,所以说 看源码一定要有目的不能为了看而看。
Java并发包源码学习之AQS框架(一)概述的更多相关文章
- Java并发包源码学习之AQS框架(四)AbstractQueuedSynchronizer源码分析
经过前面几篇文章的铺垫,今天我们终于要看看AQS的庐山真面目了,建议第一次看AbstractQueuedSynchronizer 类源码的朋友可以先看下我前面几篇文章: <Java并发包源码学习 ...
- Java并发包源码学习之AQS框架(三)LockSupport和interrupt
接着上一篇文章今天我们来介绍下LockSupport和Java中线程的中断(interrupt). 其实除了LockSupport,Java之初就有Object对象的wait和notify方法可以实现 ...
- Java并发包源码学习之AQS框架(二)CLH lock queue和自旋锁
上一篇文章提到AQS是基于CLH lock queue,那么什么是CLH lock queue,说复杂很复杂说简单也简单, 所谓大道至简: CLH lock queue其实就是一个FIFO的队列,队列 ...
- Java并发包源码学习系列:AQS共享式与独占式获取与释放资源的区别
目录 Java并发包源码学习系列:AQS共享模式获取与释放资源 独占式获取资源 void acquire(int arg) boolean acquireQueued(Node, int) 独占式释放 ...
- Java并发包源码学习系列:CLH同步队列及同步资源获取与释放
目录 本篇学习目标 CLH队列的结构 资源获取 入队Node addWaiter(Node mode) 不断尝试Node enq(final Node node) boolean acquireQue ...
- Java并发包源码学习系列:ReentrantLock可重入独占锁详解
目录 基本用法介绍 继承体系 构造方法 state状态表示 获取锁 void lock()方法 NonfairSync FairSync 公平与非公平策略的差异 void lockInterrupti ...
- Java并发包源码学习系列:ReentrantReadWriteLock读写锁解析
目录 ReadWriteLock读写锁概述 读写锁案例 ReentrantReadWriteLock架构总览 Sync重要字段及内部类表示 写锁的获取 void lock() boolean writ ...
- Java并发包源码学习系列:详解Condition条件队列、signal和await
目录 Condition接口 AQS条件变量的支持之ConditionObject内部类 回顾AQS中的Node void await() 添加到条件队列 Node addConditionWaite ...
- Java并发包源码学习系列:挂起与唤醒线程LockSupport工具类
目录 LockSupport概述 park与unpark相关方法 中断演示 blocker的作用 测试无blocker 测试带blocker JDK提供的demo 总结 参考阅读 系列传送门: Jav ...
随机推荐
- MySQL备份方式简介
MySQL备份的方式主要分为两种: 文本格式备份: 命令:mysqldump 转储文件:dump file 主要内容:数据库结构及数据(create talbe /insert) 二进制备份:这类备份 ...
- IEnumerable 遍历用法
咋一看到IEnumerable这个接口,我们可能会觉得很神奇,在一般的编程时,基本上我们是想不到去用它的,可是,俗话说得好,存在便是道理,那么,它对我们来说,能够带来哪些奇妙的事情呢? 要想弄懂它,我 ...
- 帝国cms制作手机网站
1.操作前,我们需要先对网站数据库进行备份. 接下来我们添加手机站的模板组.点击"模板", 选择"模板组管理"中的"导入/导出模板组",然后 ...
- scala中集合的交集、并集、差集
scala中有一些api设计的很人性化,集合的这几个操作是个代表: 交集: scala> Set(1,2,3) & Set(2,4) // &方法等同于interset方法 sc ...
- 爬虫例子及知识点(scrapy知识点)
新知识: 新建一个scrapy项目:scrapy startproject xxx(项目名称) 运行一个scrapy项目:scrapy crawl xxx(项目名称) 项目文件说明: 文件说明: • ...
- 使用uWSGI部署django项目
先说说什么是uWSGI吧,他是实现了WSGI协议.uwsgi.http等协议的一个web服务器,那什么是WSGI呢? WSGI是一种Web服务器网关接口.它是一个Web服务器(如nginx)与应用服务 ...
- 使用substring方法进行字符串拆分
对一个字符串进行操作,我们通常会用到这2个类:String类.StringBuffer类 而这2个类中的方法大多都是相同的,今天主要介绍他俩共同的一个特别有用的方法:substring substri ...
- css编写规范
一.注释规范 1.文件顶部注释(推荐使用) /* * @description: 中文说明 * @author: name * @update: name (2013-04-13 18:32) */ ...
- BZOJ1088: [SCOI2005]扫雷Mine
这道题A的好莫名其妙啊2333 传送门 状压DP,枚举上一个雷的分布情况(1<<3)-1,然后和当前的分布相结合,推出下一状态. //BZOJ 1088 //by Cydiater //2 ...
- HD1599 find the mincost route(floyd + 最小环)
题目链接 题意:求最小环 第一反应时floyd判断,但是涉及到最少3个点,然后就不会了,又想的是 双联通分量,这个不知道为什么不对. Floyd 判断 最小环 #include <iostrea ...