Java并发ReentrantLock
ReentrantLock简介
可重入锁,作用是使线程安全。对比于sychronized
,它能具有以下特点
- 减小资源锁的力度
- 更可控,减少发生死锁的概率
- 加锁、释放锁都是显示控制的
- 添加锁的作用时间来防止发生死锁
- 更加灵活
重入锁
可重入锁可以理解为锁的一个标识。该标识具备计数器功能。标识的初始值为0,表示当前锁没有被任何线程持有。每次线程获得一个可重入锁的时候,该锁的计数器就被加1。每次一个线程释放该所的时候,该锁的计数器就减1。前提是:当前线程已经获得了该锁,是在线程的内部出现再次获取锁的场景
ReentrantLock扩展功能
实现可轮询的锁请求
在内部锁中,要恢复死锁的唯一方法就是重启应用;而通过ReentrantLock可以规避死锁的发生
如果你不能获得所有需要的锁,那么使用可轮询的获取方式使你能够重新拿到控制权,它会释放你已经获得的这些锁,然后再重新尝试。可轮询的锁获取模式,由tryLock()方
法实现。此方法仅在调用时锁为空闲状态才获取该锁。如果锁可用,则获取锁,并立即返回值true。如果锁不可用,则此方法将立即返回值false。
/*Acquires the lock only if it is not held by another thread at the time
* of invocation.
*/
lock.tryLock()
实现可定时的锁
当使用内部锁时,一旦开始请求,锁就不能停止了,所以内部锁给实现具有时限的活动带来了风险。为了解决这一问题,可以使用定时锁。当具有时限的活
动调用了阻塞方法,定时锁能够在时间预算内设定相应的超时。如果活动在期待的时间内没能获得结果,定时锁能使程序提前返回。可定时的锁获取模式,由tryLock(long, TimeUnit)
方法实现。
实现可中断的锁获取请求
可中断的锁获取操作允许在可取消的活动中使用。lockInterruptibly()方法能够使你获得锁的时候响应中断。
ReentrantLock 与 synchronized的比较
相同点
ReentrantLock提供了synchronized类似的功能和内存语义。(提供了对资源加锁的功能)
不同点
与synchronized相比,ReentrantLock提供了更多,更加全面的功能,具备更强的扩展性。例如:时间锁等候,可中断锁等候,锁投票。
ReentrantLock还提供了条件Condition,对线程的等待、唤醒操作更加详细和灵活,所以在多个条件变量和高度竞争锁的地方,ReentrantLock更加适合(下面会阐述Condition)。
ReentrantLock提供了可轮询的锁请求。它会尝试着去获取锁,如果成功则继续,否则可以等到下次运行时处理,而synchronized则一旦进入锁请求要么成功,要么一直阻塞,所以相比synchronized而言,ReentrantLock会不容易产生死锁些。
ReentrantLock支持更加灵活的同步代码块,但是使用synchronized时,只能在同一个synchronized块结构中获取和释放。注:ReentrantLock的锁释放一定要在finally中处理,否则可能会产生严重的后果。
示例
当使用lock的时候,不能使用 CountDownLatch 来进行倒计时操作,会报出IllegalMonitorStateException
异常。因为当线程被唤醒后,资源信息与lock对象已经不是一一对应的关系,可能出现资源被A线程加锁,但是线程B尝试去解锁。
/**
* @author: n
* @date: 2019/5/13:上午11:41
*/
public class ReentrentLockTest implements Runnable{
private ReentrentLockDemo demo = new ReentrentLockDemo(10);
private static ReentrantLock lock = new ReentrantLock();
static CountDownLatch begin = new CountDownLatch(1);
static CountDownLatch end = new CountDownLatch(10);
@Override
public void run() {
try {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + "-->调用run方法被阻塞跳出run线程回到main方法线程");
//
begin.await();
//lock.tryLock();
int num = demo.splice();
System.out.println(threadName + "--->" + num);
end.countDown();
} catch (Exception e) {
e.printStackTrace();
}finally {
//lock.unlock();
}
}
public static void main(String[] args) throws Exception {
ReentrentLockTest test = new ReentrentLockTest();
for (int i = 0; i < 10; i++) {
Thread t = new Thread(test);
/**
* 进入到run方法,run方法被begin阻塞。run方法退出,重新回到main中。从而完成对所有线程的初始化
*
*
*/
// System.out.println(“”);
t.start();
}
// 调用countDown。所有线程被唤醒,开始执行run方法
begin.countDown();
end.await();
System.out.println("end");
}
}
Java并发ReentrantLock的更多相关文章
- java 并发——ReentrantLock
java 并发--ReentrantLock 简介 public class ReentrantLock implements Lock, java.io.Serializable { // 继承了 ...
- Java并发--ReentrantLock原理详解
ReentrantLock是什么? ReentrantLock重入锁,递归无阻塞的同步机制,实现了Lock接口: 能够对共享资源重复加锁,即当前线程获取该锁,再次获取不会被阻塞: 支持公平锁和非公平锁 ...
- Java并发——ReentrantLock类源码阅读
ReentrantLock内部由Sync类实例实现. Sync类定义于ReentrantLock内部. Sync继承于AbstractQueuedSynchronizer. AbstractQueue ...
- java并发-ReentrantLock的lock和lockInterruptibly的区别
ReentrantLock的加锁方法Lock()提供了无条件地轮询获取锁的方式,lockInterruptibly()提供了可中断的锁获取方式.这两个方法的区别在哪里呢?通过分析源码可以知道lock方 ...
- Java并发基础框架AbstractQueuedSynchronizer初探(ReentrantLock的实现分析)
AbstractQueuedSynchronizer是实现Java并发类库的一个基础框架,Java中的各种锁(RenentrantLock, ReentrantReadWriteLock)以及同步工具 ...
- 【Java并发编程实战】-----“J.U.C”:ReentrantLock之三unlock方法分析
前篇博客LZ已经分析了ReentrantLock的lock()实现过程,我们了解到lock实现机制有公平锁和非公平锁,两者的主要区别在于公平锁要按照CLH队列等待获取锁,而非公平锁无视CLH队列直接获 ...
- 【Java并发编程实战】-----“J.U.C”:ReentrantLock之一简介
注:由于要介绍ReentrantLock的东西太多了,免得各位客官看累,所以分三篇博客来阐述.本篇博客介绍ReentrantLock基本内容,后两篇博客从源码级别分别阐述ReentrantLock的l ...
- Java并发编程总结3——AQS、ReentrantLock、ReentrantReadWriteLock(转)
本文内容主要总结自<Java并发编程的艺术>第5章——Java中的锁. 一.AQS AbstractQueuedSynchronizer(简称AQS),队列同步器,是用来构建锁或者其他同步 ...
- Java并发系列[5]----ReentrantLock源码分析
在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可 ...
随机推荐
- LoadRunner 工具使用
LoaderRunner 第一天 1.1 性能测试基础 服务器端性能测试 1.1 什么是性能测试的本质 基于协议模拟用户发出请求(业务的模拟), 对服务器形成一定的负载,来测试服务器的性能指标是否 ...
- mediawiki资料
1.如何通过ip访问mediawiki --- http://blog.sina.com.cn/s/blog_3f2a2b8e01000awx.html 发布到外部网络,更改htfp.config里面 ...
- Linux平台下_tomcat的安装与优化
一.Tomcat介绍 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选.对于一 ...
- PAT甲级——1012 The Best Rank
PATA1012 The Best Rank To evaluate the performance of our first year CS majored students, we conside ...
- web接口测试中需要注意的点
1.接口返回 数据格式是否和预期一致.例如:要求返回json格式的数据,json数据的key命名是否正确,对应的value是否与数据库一致. 需要转换的数据是否正确转换,例如时间戳是否按正确转换为时间 ...
- derby数据库
derby数据库 https://www.cnblogs.com/zuzZ/p/8107915.html Derby数据库的使用 https://www.cnblogs.com/wkfvawl/p/1 ...
- 【Java集合】试读ArrayList源码
ArrayList简介 ArrayList 是一个数组队列,相当于 动态数组.与Java中的数组相比,它的容量能动态增长.它继承于AbstractList,实现了List, RandomAccess, ...
- 使用 FreeMarker模板 Springboot 发送邮件
四.使用 FreeMarker模板 HTML 标签的字符串拼接是一件很棘手的事.因为在你的大脑中解析HTML标签并想象它在渲染时会是什么样子是挺困难的.而将HTML混合在Java代码中又会使得这个问题 ...
- JVM组成与作用
class loader 类加载器:加载类文件到内存.Class loader只管加载,只要符合文件结构就加载,至于能否运行,它不负责,那是有Exectution Engine 负责的.exectio ...
- openssl内存分配,查看内存泄露
openssl内存分配 用户在使用内存时,容易犯的错误就是内存泄露.当用户调用内存分配和释放函数时,查找内存泄露比较麻烦.openssl提供了内置的内存分配/释放函数.如果用户完全调用openssl的 ...