【Java并发编程实战】----- AQS(二):获取锁、释放锁
上篇博客稍微介绍了一下AQS,下面我们来关注下AQS的所获取和锁释放。
AQS锁获取
AQS包含如下几个方法:
acquire(int arg):以独占模式获取对象,忽略中断。
acquireInterruptibly(int arg): 以独占模式获取对象,如果被中断则中止。
acquireShared(int arg): 以共享模式获取对象,忽略中断。
acquireSharedInterruptibly(int arg)以共享模式获取对象,如果被中断则中止。
tryAcquire(int arg):试图在独占模式下获取对象状态。
tryAcquireNanos(int arg, long nanosTimeout):试图以独占模式获取对象,如果被中断则中止,如果到了给定超时时间,则会失败。
tryAcquireShared(int arg):试图在共享模式下获取对象状态。
tryAcquireSharedNanos(int arg, long nanosTimeout):试图以共享模式获取对象,如果被中断则中止,如果到了给定超时时间,则会失败。
对于lock.lock()最终都会调用AQS的acquire()方法,Semaphore.acquire()最终会调用AQS的acquireSharedInterruptibly()方法,其中acquire()源代码如下:
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
tryAcquire:去尝试获取锁,获取成功则设置锁状态并返回true,否则返回false。
addWaiter:将当前线程加入到CLH队列队尾。
acquireQueued:当前线程会根据公平性原则来进行阻塞等待,直到获取锁为止;并且返回当前线程在等待过程中有没有中断过。
selfInterrupt:产生一个中断。
其主要流程如下:

1、首先线程尝试获取锁,如果成功则直接返回,不成功则新建一个Node节点并添加到CLH队列中。tryAcquire尝试获取锁,addWaiter则新建节点并添加到CLH队列中。其中tryAcquire,AQS并没有提供实现,它仅仅只是抛出一个异常,具体的实现需要各个锁自己实现。
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
addWaiter后面讲述。
2、acquireQueued主要功能是根据该节点寻找CLH队列的头结点,并且尝试获取锁,判断是否需要挂起,并且返回挂起标识。如下:
final boolean acquireQueued(final Node node, int arg) {
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} catch (RuntimeException ex) {
cancelAcquire(node);
throw ex;
}
}
在acquireQueued()内部仍然调用tryAcquire()来获取锁。更多详情请参考:【Java并发编程实战】—–“J.U.C”:ReentrantLock之二lock方法分析
selfInterrupt:产生一个中断。如果在acquireQueued()中当前线程被中断过,则需要产生一个中断。
private static void selfInterrupt() {
Thread.currentThread().interrupt();
}
AQS锁释放
AQS释放锁的方法主要有:
release(int arg):以独占模式释放对象。
releaseShared(int arg): 以共享模式释放对象
tryRelease(int arg):试图设置状态来反映独占模式下的一个释放。
tryReleaseShared(int arg):试图设置状态来反映共享模式下的一个释放。
释放锁相对于获取锁来说还是比较简单的,其主要流程如下:

其代码如下(release()):
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
tryeRelease():尝试释放锁,AQS也同样没有提供实现,具体实现方法要其子类自己内部实现,AQS仅仅只是抛出一个异常。
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
unparkSuccessor:用于唤醒节点。更多,请参考:【Java并发编程实战】—–“J.U.C”:ReentrantLock之三unlock方法分析
参考文献:
【Java并发编程实战】----- AQS(二):获取锁、释放锁的更多相关文章
- java并发编程实战《二十一》无锁工具类
不安全的累加代码,如下 1 public class Test { 2 long count = 0; 3 void add10K() { 4 int idx = 0; 5 while(idx++ & ...
- java并发编程实战《二》java内存模型
Java解决可见性和有序性问题:Java内存模型 什么是 Java 内存模型? Java 内存模型是个很复杂的规范,可以从不同的视角来解读,站在我们这些程序员的视角,本质上可以理解为, Java 内存 ...
- 【Java并发编程实战】-----“J.U.C”:锁,lock
在java中有两种方法实现锁机制,一种是在前一篇博客中([java7并发编程实战]-----线程同步机制:synchronized)介绍的synchronized,而另一种是比synchronized ...
- 《Java并发编程实战》第十三章 显示锁 读书笔记
一.Lock与 ReentrantLock Lock 提供一种无条件的.可轮询的.定时的.可中断的锁获取操作,全部加锁和解锁的方法都是显式的. public interface Lock { void ...
- 《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁
第13章 显示锁 终于看到了这本书的最后一本分,呼呼呼,真不容易.其实说实在的,我不喜欢半途而废,有其开始,就一定要有结束,否则的话就感觉哪里乖乖的. java5.0之前,在协调对共享对象的访问时可以 ...
- java并发编程实战:第十三章----显示锁
一.Lock与ReentrantLock Lock接口中定义了一种无条件.可轮询的.定时的以及可中断的锁获取操作,所有加锁和解锁的方法都是显式的. 1 public interfece Lock 2 ...
- 那些年读过的书《Java并发编程实战》二、如何设计线程安全类
1.设计线程安全类的过程 设计线程安全类的过程就是设计对象状态并发访问下线程间的协同机制(在不破坏对象状态变量的不变性条件的前提下). (1)构建线程安全类的三个基本要素: 1)找出构成对象状态的所有 ...
- 读书笔记-----Java并发编程实战(二)对象的共享
public class NoVisibility{ private static boolean ready; private static int number; private static c ...
- Java并发编程实战 第13章 显式锁
接口Lock的实现类: ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock Reentra ...
随机推荐
- 微信应用号(小程序)开发IDE配置(第一篇)
2016年9月22日凌晨,微信宣布“小程序”问世,当然只是开始内测了,微信公众平台对200个服务号发送了小程序内测邀请.那么什么是“小程序”呢,来看微信之父怎么说 看完之后,相信大家大概都有些明白了吧 ...
- .net core快速上手
2014年11月12日的Connect ();开发者活动上宣布将.NET堆栈基于MIT协议开源,并且提供开源保证,托管在Github上.当时的版本与最终目标相距甚远,然而有一点可以肯定的是,这是一个与 ...
- 回首经典的SQL Server 2005
原创文章转载请注明出处:@协思, http://zeeman.cnblogs.com SQL Server是我使用时间最长的数据库,算起来已经有10年了.上世纪90年代,微软在软件开发的所有领域高歌猛 ...
- CodeSimth - .Net Framework Data Provider 可能没有安装。解决方法
今天想使用CodeSimth生成一个sqlite数据库的模板.当添加添加数据库的时候发现: .Net Framework Data Provider 可能没有安装. 下面找到官方的文档说明: SQLi ...
- Vue + Webpack + Vue-loader 系列教程(1)功能介绍篇
原文地址:https://lvyongbo.gitbooks.io/vue-loader/content/ Vue-loader 是什么? vue-loader 是一个加载器,能把如下格式的 Vue ...
- Android和JavaScript相互调用的方法
转载地址:http://www.jb51.net/article/77206.htm 这篇文章主要介绍了Android和JavaScript相互调用的方法,实例分析了Android的WebView执行 ...
- Java中Comparable与Comparator的区别
相同 Comparable和Comparator都是用来实现对象的比较.排序 要想对象比较.排序,都需要实现Comparable或Comparator接口 Comparable和Comparator都 ...
- redis集成到Springmvc中及使用实例
redis是现在主流的缓存工具了,因为使用简单.高效且对服务器要求较小,用于大数据量下的缓存 spring也提供了对redis的支持: org.springframework.data.redis.c ...
- angular2系列教程(六)两种pipe:函数式编程与面向对象编程
今天,我们要讲的是angualr2的pipe这个知识点. 例子
- WebApi基于Token和签名的验证
最近一段时间在学习WebApi,涉及到验证部分的一些知识觉得自己并不是太懂,所以来博客园看了几篇博文,发现一篇讲的特别好的,读了几遍茅塞顿开(都闪开,我要装逼了),刚开始读有些地方不理解,所以想了很久 ...