Java多线程之ReentrantLock重入锁简介与使用教程
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6543947.html
我们知道,线程安全问题需要通过线程之间的同步来解决,而同步大多使用syncrhoized关键字,简单方便。但是syncrhoized功能上较单一,为此,concurrent包为我们提供了额外的几种同步控制工具,让我们可以根据不同的同步需求更加灵活地选择同步工具。
一:ReentrantLock(重入锁)
ReentrantLock具有可重入、可中断、可限时申请、可公平获取等特点。
它的使用很简单:1:创建一个reentrantlock对象;2:在需要同步控制的代码块的起始处用 lock.lock() 加锁;3:在退出同步控制块处 lock.unlock() 解锁。
1)可重入
ReentrantLock可以重复获得同一把锁,即:在一个线程中,一个reentrantlock对象可以重复调用 lock() 申请这个锁对象进行加锁。
我们知道。如果一个线程申请同步锁时,如果锁被占用了就会导致阻塞,等待请求的锁释放,若是请求的锁刚好是自己以及在使用的锁呢?难道也要导致阻塞吗?可重入性就是为了解决这个问题,若当前线程请求的锁是自己已获得的锁,则使锁的获取计数器+1而已,不会自己阻塞自己,线程继续照常执行。
但是可重入性也要求了,一个线程请求了多少次同一个锁,那么就要相应地在结束时释放多少次。
lock.lock();
lock.lock();
try
{
i++; }
finally
{
lock.unlock();
lock.unlock();
}
2)可中断
如果有两个线程,一个在lock1.lock()后申请了lock2.lock(),一个在lock2.lock()后申请了lock1.lock(),启动这两个线程。这两个线程都在等待对方释放掉已申请的lock,好让自己获得第二个lock而进行下去,这样的话就会导致死锁。我们知道死锁是由于资源请求存在环路导致的,只要打破这个环路即可让大部分请求得到满足,打破就是我们说的——中断。我们可以通过中断其中一个线程,使其让出所占用的资源(已获得的lock),则另一个线程即可获得两个lock而得以继续进行下去。
reentrantlock的可中断锁是通过 lockInterruptibly() 获取的,而不是普通的 lock()方法。
public static ReentrantLock lock1 = new ReentrantLock();
lock1.lockInterruptibly();
我们怎么知道死锁并解决呢?这需要用到ThreadMXBean(Java虚拟机线程管理接口)中提供的一系列方法,我们可以通过 ManagementFactory .getThreadMXBean();来获得一个线程管理接口的实现类,里面实现了ThreadMXBean中的线程管理方法,罗列如下:
| 方法摘要 | |
|---|---|
ThreadInfo[] |
dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers) 返回所有活动线程的线程信息,并带有堆栈跟踪和同步信息。 |
long[] |
findDeadlockedThreads() 查找因为等待获得对象监视器或可拥有同步器而处于死锁状态的线程循环。 |
long[] |
findMonitorDeadlockedThreads() 找到处于死锁状态(等待获取对象监视器)的线程的周期。 |
long[] |
getAllThreadIds() 返回活动线程 ID。 |
long |
getCurrentThreadCpuTime() 返回当前线程的总 CPU 时间(以毫微秒为单位)。 |
long |
getCurrentThreadUserTime() 返回当前线程在用户模式中执行的 CPU 时间(以毫微秒为单位)。 |
int |
getDaemonThreadCount() 返回活动守护线程的当前数目。 |
int |
getPeakThreadCount() 返回自从 Java 虚拟机启动或峰值重置以来峰值活动线程计数。 |
int |
getThreadCount() 返回活动线程的当前数目,包括守护线程和非守护线程。 |
long |
getThreadCpuTime(long id) 返回指定 ID 的线程的总 CPU 时间(以毫微秒为单位)。 |
ThreadInfo |
getThreadInfo(long id) 返回指定 id 的不具有堆栈跟踪的线程的线程信息。 |
ThreadInfo[] |
getThreadInfo(long[] ids) 返回其 ID 在输出数组 ids 中的每个线程的线程信息,这些线程不具有堆栈跟踪。 |
ThreadInfo[] |
getThreadInfo(long[] ids, boolean lockedMonitors, boolean lockedSynchronizers) 返回每个线程的线程信息,线程 ID 位于输入数组 ids 中,带有堆栈跟踪和同步信息。 |
ThreadInfo[] |
getThreadInfo(long[] ids, int maxDepth) 返回其 ID 在输入数组 ids 中的每个线程的线程信息,并带有指定堆栈追踪元素数的堆栈追踪。 |
ThreadInfo |
getThreadInfo(long id, int maxDepth) 返回指定 id 的线程的线程信息,并带有指定堆栈追踪元素数的堆栈追踪。 |
long |
getThreadUserTime(long id) 返回指定 ID 的线程在用户模式中执行的 CPU 时间(以毫微秒为单位)。 |
long |
getTotalStartedThreadCount() 返回自从 Java 虚拟机启动以来创建和启动的线程总数目。 |
boolean |
isCurrentThreadCpuTimeSupported() 测试 Java 虚拟机是否支持当前线程的 CPU 时间测量。 |
boolean |
isObjectMonitorUsageSupported() 测试 Java 虚拟机是否支持使用对象监视器的监视。 |
boolean |
isSynchronizerUsageSupported() 测试 Java 虚拟机是否支持使用可拥有同步器的监视。 |
boolean |
isThreadContentionMonitoringEnabled() 测试是否启用了线程争用监视。 |
boolean |
isThreadContentionMonitoringSupported() 测试 Java 虚拟机是否支持线程争用监视。 |
boolean |
isThreadCpuTimeEnabled() 测试是否启用了线程 CPU 时间测量。 |
boolean |
isThreadCpuTimeSupported() 测试 Java 虚拟机实现是否支持任何线程的 CPU 时间测量。 |
void |
resetPeakThreadCount() 将峰值线程计数重置为当前活动线程的数量。 |
void |
setThreadContentionMonitoringEnabled(boolean enable) 启用或禁用线程争用监视。 |
void |
setThreadCpuTimeEnabled(boolean enable) 启用或禁用线程 CPU 时间测量。 |
从上面我们可以看到,通过ThreadMXBean我们可以获取虚拟机当前运行的所以线程的信息,包括 线程ID、存活的线程、死锁的线程等等信息。
所以,我们可以通过ThreadMXBean获取到由reentrantlock的lockInterruptibly()导致的死锁的随便一个线程的ID,然后通过 线程的interrupt() 方法自动中断自己,就可以使得死锁环中其他线程得以顺利执行。
3)可限时申请锁
reentrantlock对象可以限时申请获得锁,如果在限定时间内没能获取则放弃申请,在没锁的情况下执行代码(此时是不同步进行,线程不安全)。这样就不会由于申请被占用的锁而阻塞线程。
限时申请锁是通过 lock.trylock(num,unit)实现的,unit是时间单元,可以选择秒、分钟、小时、天等,num是数量,指定有多少个时间单元时间用来尝试获得锁。
public static ReentrantLock lock = new ReentrantLock();
lock.tryLock(5, TimeUnit.SECONDS);
4)可公平获取
一般的锁不是公平的,不会说先申请的线程就先获得锁,这样容易使得某一个线程一直处于申请获得锁的状态,即——饥饿。
ReentrantLock可以在创建时通过构造参数指定是不是公平锁,当作为公平锁创建时,申请获得该锁的线程们将严格按照“先申请先获得”的顺序来使用该锁。
public ReentrantLock(boolean fair) public static ReentrantLock fairLock = new ReentrantLock(true);
Java多线程之ReentrantLock重入锁简介与使用教程的更多相关文章
- java并发系列(三)-----ReentrantLock(重入锁)功能详解和应用演示
1. ReentrantLock简介 jdk中独占锁的实现除了使用关键字synchronized外,还可以使用ReentrantLock.虽然在性能上ReentrantLock和synchronize ...
- java高并发系列 - 第12天JUC:ReentrantLock重入锁
java高并发系列 - 第12天JUC:ReentrantLock重入锁 本篇文章开始将juc中常用的一些类,估计会有十来篇. synchronized的局限性 synchronized是java内置 ...
- java并发系列(四)-----源码角度彻底理解ReentrantLock(重入锁)
1.前言 ReentrantLock可以有公平锁和非公平锁的不同实现,只要在构造它的时候传入不同的布尔值,继续跟进下源码我们就能发现,关键在于实例化内部变量sync的方式不同,如下所示: /** * ...
- ReentrantLock(重入锁)以及公平性
ReentrantLock(重入锁)以及公平性 标签(空格分隔): java NIO 如果在绝对时间上,先对锁进行获取的请求一定被先满足,那么这个锁是公平的,反之,是不公平的,也就是说等待时间最长的线 ...
- 从源码角度彻底理解ReentrantLock(重入锁)
目录 1.前言 2.AbstractQueuedSynchronizer介绍 2.1 AQS是构建同步组件的基础 2.2 AQS的内部结构(ReentrantLock的语境下) 3 非公平模式加锁流程 ...
- ReentrantLock(重入锁)的源码解析
转自:从源码角度彻底理解ReentrantLock(重入锁)](https://www.cnblogs.com/takumicx/p/9402021.html)) 公平锁内部是FairSync,非公平 ...
- Java多线程之ReentrantLock与Condition
一.ReentrantLock 1.ReentrantLock简介 ReentrantLock是一个可重入的互斥锁,又被称为“独占锁”.ReentrantLock 类实现了 Lock ,它拥有与 sy ...
- ReentrantLock 重入锁(下)
前沿: ReentrantLock 是java重入锁一种实现,在java中我们通常使用ReentrantLock 和 synchronized来实现锁功能,本篇通过例子来理解下Reentr ...
- java多线程之ReentrantLock
前言 相信学过java的人都知道 synchronized 这个关键词,也知道它用于控制多线程对并发资源的安全访问,兴许,你还用过Lock相关的功能,但你可能从来没有想过java中的锁底层的机制是怎么 ...
随机推荐
- ListView单条刷新的方法
我们一般会调用notifydatasetchange通知listView刷新界面.但会造成getView方法被多次调用(画面上能显示多少就会被调用多少次),如果是很明确的知道只更新了list中的某一个 ...
- 让java从Mysql返回多个ResultSet
首先,JDBC对于SQLSERVER来说默认是支持返回,但对于MySql来说,只默认支持存储过程返回多个ResultSet,那对于手写SQL怎么办. 其实很简单,只要一个在连接字符串中加一个参数:al ...
- SVG.js 引用获取整理
一.SVG.get() 根据id获取元素 var draw = SVG('svg1').size(300, 300); var circle = draw.circle(50); circle.fil ...
- Springboot 之 自定义配置文件及读取配置文件注意:配置文件中的字符串不要有下划线 .配置中 key不能带下划线,value可以(下划线的坑,坑了我两天..特此纪念)
注意:配置文件中的字符串不要有下划线 .配置中 key不能带下划线,value可以 错误的.不能读取的例子: mySet .ABAP_AS_POOLED = ABAP_AS_WITH_P ...
- float,double等精度丢失问题 float,double内存表示
问题提出:12.0f-11.9f=0.10000038,"减不尽"为什么? 来自MSDN的解释: http://msdn.microsoft.com/zh-cn/c151dt3s. ...
- 使用C++ Builder XE5获取Sensor值之Light Sensor
献上代码C++代码,仅供參考. 若使用Delphi.请參考文献,http://blogs.embarcadero.com/davidi/2013/12/02/43032/ 一定记得要安装FireMon ...
- Ubuntu环境变量解析
在Ubuntu中有如下几个文件可以设置环境变量 /etc/profile:在登录时,操作系统定制用户环境时使用的第一个文件,此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行. /e ...
- xgboost入门与实战(实战调参篇)
https://blog.csdn.net/sb19931201/article/details/52577592 xgboost入门与实战(实战调参篇) 前言 前面几篇博文都在学习原理知识,是时候上 ...
- 转:从头开始编写基于隐含马尔可夫模型HMM的中文分词器
http://blog.csdn.net/guixunlong/article/details/8925990 从头开始编写基于隐含马尔可夫模型HMM的中文分词器之一 - 资源篇 首先感谢52nlp的 ...
- Linq-排序Order By
适用场景:对查询出的语句进行排序,比如按时间排序等等. 说明:按指定表达式对集合排序:延迟,:按指定表达式对集合排序:延迟,默认是升序,加上descending表示降序,对应的扩展方法是OrderBy ...