JUC中Lock和ReentrantLock介绍及源码解析
Lock框架是jdk1.5新增的,作用和synchronized的作用一样,所以学习的时候可以和synchronized做对比。在这里先和synchronized做一下简单对比,然后分析下Lock接口以及ReentrantLock的源码和说明。具体的其他的Lock实现的分析在后面会慢慢介绍。
Lock框架和synchronized
有关synchronized的作用和用法不在具体说明,应该都很熟悉了。而Lock有着和synchronized一样的语意,但是比synchronized多了一些功能,单单就从Lock接口定义来看,比synchronized多出来的功能有:
- 可中断的获取锁,就是获取锁的线程可以响应中断。
- 可以尝试获取锁,也就是非阻塞获取锁,一个线程可以尝试去获取锁,获取成功就持有锁并返回true,否则返回false。
- 带超时的尝试获取锁,就是在尝试获取锁的时候,会有超时时间,当到达了指定的时间后,还未获取到锁,就返回false。
除了定义之外,Lock框架还和synchronized有不一样的是:
- Lock需要显示的加锁和释放锁,而且一定要在finally中去释放锁。而synchronized则不需要我们去关心锁的释放。
- 锁的公平性,Lock接口并没有定义有关公平性的方法,而是在具体的实现类中使用AQS来实现锁的公平性。
Lock接口源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public interface Lock {
//获取锁,获取到锁后返回
//注意一定要记得释放锁
void lock();
//可中断的获取锁
//获取锁的时候,如果线程正在等待获取锁,则该线程能响应中断
void lockInterruptibly() throws InterruptedException;
//尝试获取锁,当线程获取锁的时候,获取成功与否都会立即返回
//不会一直等着去获取锁
boolean tryLock();
//带有超时时间的尝试获取锁
//在一定的时间内获取到锁会返回true
//在这段时间内被中断了,会返回
//在这段时间内,没有获取到锁,会返回false
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
//释放锁
void unlock();
//获取一个Condition对象。
Condition newCondition();
}
1 |
public interface Lock {
|
Lock接口的定义并不复杂,获取锁释放锁以及非阻塞式的获取锁等方法的定义。其实想象一下日常使用的时候,也大概是如此,获取锁,释放锁,获取锁的时候没有得到锁,我就转一圈回来再试试,等到一定时间之后,我就不要了,走了。接口的定义没有太多要说的,接下来看Lock接口的实现。
Lock接口的实现
Lock接口主要的实现是ReentrantLock重入锁,另外还有ConcurrentHashMap中的Segment继承了ReentrantLock,在ReentrantReadWriteLock中的WriteLock和ReadLock也实现了Lock接口。
ReentrantLock
ReentrantLock是一个可重入的互斥锁,等同于synchronized,但是比synchronized更强大灵活,减少死锁发生的概率。我们上面说Lock框架提供了公平锁的机制,就是在ReentrantLock中有提供公平锁机制的实现,默认为非公平锁。
在继续看ReentrantLock的各个方法实现之前,首先需要了解下内部是怎么实现公平锁和非公平锁的,其实想一下也简单,比如我就是一可重入锁ReentrantLock,你想从我这获得到公平的还是不公平的,但是不能我说什么就是什么,我这里有一个天平(AQS),这个是大家公认的可以实现公平和不公平的机器,你找我要,我就给天平说一声,他来操作,然后我再把结果给你。(越描述越复杂!)。几乎ReentrantLock中所有的操作都会交给Sync去实现。
有关AQS这里不做介绍,在AQS专门的文章有介绍,请自行查阅把。接下来就看看我拿着的两把锁,公平和不公平。
Sync
Sync是公平和非公平两种的基类,直接看代码,看不明白的话,可以先看下面公平和非公平的解析,然后再返回来:
1 |
//继承自AQS |
FairSync
公平锁的实现,有关公平的实现,是此类进行处理的。
1 |
//继承自Sync |
可以看到公平的tryAcquire在获取锁的开始只调用一次,获取到就获取到了,或者已经获取到增加重入数,没有获取到就返回false,如果返回false的话,AQS就会将其加入到队列中一直尝试获取。
NonfairSync
1 |
//也是继承自Sync |
公平和非公平的区别
上面看完了代码,有点模糊,感觉代码都差不多,到底公平和非公平差别在哪里。首先看下公平的锁获取,公平锁获取会直接调用acquire方法,acquire方法并不是直接去获取锁,而是调用公平的tryAcquire方法,公平的tryAcquire方法首先获取到当前同步器状态,如果没有人用同步器,也就是状态为0,会先去判断有没有人比我等的时间更长,有的话我就不能获取锁,而是让别人先去;如果我是等待最长的那个,我就去使用CAS更改状态,获取锁。
而非公平的实现是,我上来就直接使用CAS获取锁,不问别人是不是等着很长时间了,我获取到了就是我的了,我获取不到,再调用acquire方法,然后acquire方法中调用非公平的tryAcquire方法,非公平的tryAcquire方法也是很直接,如果当前锁没有人用,也就是state为0,我不管有没有人比我等的时间长,我就去获取,然后设置独占。
公平锁,获取锁首先去尝试,没有的话就排队,轮到我之后,还要去问一下有没有等的时间更长的。非公平锁则是不排队,直接上,没有获取到,我也尝试获取,尝试获取的时候我还是直接上,不管其他人。
了解完公平和非公平锁,再去看其他方法就没那么难了。
ReentrantLock构造函数
1 |
//可以看到,默认是非公平的 |
还可以指定公平性
1 |
public ReentrantLock(boolean fair) {
|
lock方法
1 |
//直接调用公平或者非公平的同步器的lock方法 |
lock方法有三种情况:
- 如果锁没有被其他线程持有,当前线程立即获得锁并返回,同步器状态设为1。
- 如果当前线程已经持有锁,则状态加1,并立即返回。
- 如果锁被其他线程持有,当前线程挂起直到获取到锁,然后返回,同步器设为1。
lockInterruptibly方法
1 |
//可中断的获取锁 |
获取锁,可以被Thread.interrupt打断。也有三种情况:
- 如果锁没有被其他线程持有,当前线程立即获得锁并返回,同步器状态设为1。
- 如果当前线程已经持有锁,则状态加1,并立即返回。
如果锁被其他线程持有,当前线程会挂起去获取锁,在这个过程会有两种情况:
- 当前线程获取到了锁,返回,同步器状态设置1。
- 当前线程被中断了,会抛出InterruptedException异常,并清除中断状态。
tryLock方法
1 |
//尝试获取锁,不会阻塞,成功与否都会直接返回 |
使用非公平的锁获取,如果使用了公平的,获取的时候还要判断别人是不是了好久,而非公平的nonfairTryAcquire,能获取就直接获取到,获取不到就返回false,比较直接。
如果不想破坏公平性,可以使用带有超时时间的tryLock方法。
带超时的tryLock方法
1 |
//在超时间内,并且没有被打断,锁没有被其他线程持有,就立即获取到锁并返回 |
如果使用的是公平锁,如果有其他等的时间更长的线程,即便现在锁没有人持有,当前线程也不会获取到锁,给等的时间更长的去获取。
unlock方法
1 |
//释放锁 |
newCondition方法
1 |
//返回一个新的Condition实例 |
返回的Condition实例的方法,其实和Object的wait,notify,notifyAll方法的作用一样。
其他方法
1 |
//重入次数 |
ReentrantLock和synchronized的区别
ReentrantLock和synchronized很类似,但是比synchronized多了更多功能,比如可中断锁,锁可以带超时时间,可以尝试非阻塞获取锁等。ReentrantLock还提供了条件Condition,跟Object的wait/notify类似,但是在多个条件变量和高度竞争锁的地方,ReentrantLock更加合适。
另外AQS是重点,一定要多学几遍,学会了,才能掌握锁(我还不太明白!)。
有关其他实现,比如ReentrantReadWriteLock的ReadLock和WriteLock以及ConcurrentHashMap中的Segment会另行介绍。
JUC中Lock和ReentrantLock介绍及源码解析的更多相关文章
- Android IntentService使用介绍以及源码解析
版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.IntentService概述及使用举例 IntentService内部实现机制用到了HandlerThread,如果对HandlerThrea ...
- IPerf——网络测试工具介绍与源码解析(4)
上篇随笔讲到了TCP模式下的客户端,接下来会讲一下TCP模式普通场景下的服务端,说普通场景则是暂时不考虑双向测试的可能,毕竟了解一项东西还是先从简单的情况下入手会快些. 对于服务端,并不是我们认为的直 ...
- Spring中AOP相关的API及源码解析
Spring中AOP相关的API及源码解析 本系列文章: 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configuration注解? 谈谈Spring ...
- Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析
Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析 说明:Java生鲜电商平台中,由于服务进行了拆分,很多的业务服务导致了请求的网络延迟与性能消耗,对应的这些问题,我们 ...
- IPerf——网络测试工具介绍与源码解析(2)
对于IPerf源码解析,我是基于2.0.5版本在Windows下执行的情况进行分析的,提倡开始先通过对源码的简单修改使其能够在本地编译器运行起来,这样可以打印输出一些中间信息,对于理解源码的逻辑,程序 ...
- IPerf——网络测试工具介绍与源码解析(1)
IPerf是一个开源的测试网络宽带并能统计并报告延迟抖动.数据包丢失率信息的控制台命令程序,通过参数选项可以方便地看出,通过设置不同的选项值对网络带宽的影响,对于学习网络编程还是有一定的借鉴意义,至少 ...
- ReentrantLock与synchronized 源码解析
一.概念及执行原理 在 JDK 1.5 之前共享对象的协调机制只有 synchronized 和 volatile,在 JDK 1.5 中增加了新的机制 ReentrantLock,该机制的诞生并 ...
- Android HandlerThread使用介绍以及源码解析
摘要: 版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.HandlerThread的介绍及使用举例 HandlerThread是什么鬼?其本质就是一个线程,但是Han ...
- vue系列---Mustache.js模板引擎介绍及源码解析(十)
mustache.js(3.0.0版本) 是一个javascript前端模板引擎.官方文档(https://github.com/janl/mustache.js) 根据官方介绍:Mustache可以 ...
随机推荐
- 使用XStream是实现XML与Java对象的转换(1)--简介及入门示例
一.简单介绍 XStream是thoughtworks开发的开源框架,用于实现XML数据于Java对象.Json数据的转换.它不需要schema或其他的mapping文件就可以进行java对象和xml ...
- jQuery学习小结
1.jQuery hide() 和 show() 通过 jQuery,您可以使用 hide() 和 show() 方法来隐藏和显示 HTML 元素: $("#hide").clic ...
- C#逻辑面试题汇总【不断更新中】
(1)产生本月的月历,参考样式: 1 2 3 4 5 6 SU MO TU WE TH FR SA 01 02 03 04 05 06 07 08 09 10 11 12 13 14 ...
- jvm比较详尽的内存结构
JVM内存结构 2012-09-17 15:27:59 分类: Java 本文转自:http://www.blogjava.net/nkjava/archive/2012/03/14/371831. ...
- IT实用技术资源整理
花了一下午整理出了常用的且比较实用的网站,以及一些收藏的资源,希望对大家有帮助! 常用技术资料 Python中文开发者社区 Python中文官方文档 开源中国社区 Python机器学习 jmeter插 ...
- 使用 JMeter 进行压力测试
一.前言 压力测试是每一个Web应用程序上线之前都需要做的一个测试,他可以帮助我们发现系统中的瓶颈问题,减少发布到生产环境后出问题的几率:预估系统的承载能力,使我们能根据其做出一些应对措施.所以压力测 ...
- 【.NET Core】ASP.NET Core之IdentityServer4(1):快速入门
[.NET Core]ASP.NET Core之IdentityServer4 本文中的IdentityServer4基于上节的jenkins 进行docker自动化部署. 使用了MariaDB,EF ...
- 深度学习之 TensorFlow(二):TensorFlow 基础知识
1.TensorFlow 系统架构: 分为设备层和网络层.数据操作层.图计算层.API 层.应用层.其中设备层和网络层.数据操作层.图计算层是 TensorFlow 的核心层. 2.TensorFlo ...
- Opencv3.1+python2.7的CentOS7安装
http://blog.csdn.NET/daunxx/article/details/50506625 转载注释:有些包名和系统包名并不匹配,yum install 找不到的时候,可以yum sea ...
- Django若干新版本一些新特性
前面那篇文章简单总结了1.9版本的新特性,其实这是我一直想做的一件事情,不过因为对于工作不是那么紧急需要,所以一直被搁浅着,今天既然做了就多做一点吧 Django1.8的新特性大概(2015年4月发布 ...