【java并发编程】ReentrantLock 可重入读写锁

一、ReentrantLock可重入锁
可重入锁ReentrantLock 是一个互斥锁,即同一时间只有一个线程能够获取锁定资源,执行锁定范围内的代码。这一点与synchronized 关键字十分相似。其基本用法代码如下:
Lock lock = new ReentrantLock(); //实例化锁
//lock.lock(); //上锁
boolean locked = lock.tryLock(); //尝试上锁
if(locked){
try {
//被锁定的同步代码块,同时只能被一个线程执行
}finally {
lock.unlock(); //放在finally代码块中,保证锁一定会被释放
}
}
通过lock函数获取锁,通过unlock函数释放锁。非常重要的是,需要把需要同步执行的代码放入 try/finally 代码块中,并在finally中将锁释放。ReentrantLock是可重入锁,即:(lock/unlok)动作里面可以嵌套(lock/unlock),针对同一个锁可以多次嵌套使用,不会产生死锁。但是lock函数与unlock函数在代码中必须成对出现,否则会出现死锁。
二、ReentrantReadWriteLock读写锁
ReentrantReadWriteLock类为读写锁实现类,针对某一个对象或可变变量,只要没有线程在修改它,这个对象或可变变量就可以同时被多个线程读取。ReentrantReadWriteLock将锁分为读锁和写锁,只要没有线程持有写锁的情况下,读锁可以由多个线程同时持有。
- 读锁-如果没有线程获取或请求写锁,那么多个线程可以获取读锁
- 写锁-如果没有线程在读或写,那么只有一个线程可以获得写锁
简单的说就是ReentrantReadWriteLock可以保证最多同时有一个线程在写数据,或者可以同时有多个线程读数据。因此使用ReentrantReadWriteLock,在读操作比写操作更频繁的情况下,可以提高程序的性能和吞吐量。
下面我们用一个简单的例子,来解读一下如何应用读写锁。
public class TestReadWriteLock {
//可以同时执行3个线程任务的线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
//读写目标,写线程放入数据到map,读线程从map读取数据
Map<String, String> map = new HashMap<>();
//读写锁操作对象
ReadWriteLock lock = new ReentrantReadWriteLock();
//写操作函数
public void write(){
executor.submit(() -> { //线程池提交写操作任务
lock.writeLock().lock(); //加写锁
try {
map.put("key", "val"); //写数据操作
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock(); //释放写锁
}
});
}
//读操作函数
public void read(){
lock.readLock().lock(); //加读锁
System.out.println(Thread.currentThread().getName() + "加读锁");
try {
System.out.println(map.get("key")); //读数据操作
} finally {
lock.readLock().unlock(); //释放读锁
System.out.println(Thread.currentThread().getName() + "释放读锁");
}
}
}
三、读锁之间不互斥
我们写一个测试方法,通过打印输出来理解读写锁控制代码的执行顺序。
//测试
public static void main(String[] args) {
TestReadWriteLock test = new TestReadWriteLock();
test.write(); //提交一次写操作任务,写一条数据
Runnable readTask = test::read; //线程方法read,实现线程Runnable接口的简便写法
test.executor.submit(readTask); //读1次(新读线程)
test.executor.submit(readTask); //读2次 (新读线程)
test.executor.shutdown();
}
执行上面的代码,可能会出现下面的输出
pool-1-thread-2加读锁
pool-1-thread-3加读锁
val
val
pool-1-thread-3释放读锁
pool-1-thread-2释放读锁
在pool-1-thread-2没有释放读锁情况下,pool-1-thread-3可以再次加读锁,并且都正确的读取到数据val。说明读锁之间是不互斥的。但是,在进行读操作(读锁生效)的时候,写操作是无法进行的(无法获取写锁),所以ReentrantReadWriteLock不支持同时加读锁和写锁。 这个结论我可以负责任告诉大家,这里我就不做验证了!
欢迎关注我的博客,更多精品知识合集
本文转载注明出处(必须带连接,不能只转文字):字母哥博客 - zimug.com
觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力!。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。
- 《kafka修炼之道》
- 《手摸手教你学Spring Boot2.0》
- 《Spring Security-JWT-OAuth2一本通》
- 《实战前后端分离RBAC权限管理系统》
- 《实战SpringCloud微服务从青铜到王者》
【java并发编程】ReentrantLock 可重入读写锁的更多相关文章
- Java并发编程:同步锁、读写锁
之前我们说过线程安全问题可以用锁机制来解决,即线程必要要先获得锁,之后才能进行其他操作.其实在 Java 的 API 中有这样一些锁类可以提供给我们使用,与其他对象作为锁相比,它们具有更强大的功能. ...
- 聊聊高并发(二十九)解析java.util.concurrent各个组件(十一) 再看看ReentrantReadWriteLock可重入读-写锁
上一篇聊聊高并发(二十八)解析java.util.concurrent各个组件(十) 理解ReentrantReadWriteLock可重入读-写锁 讲了可重入读写锁的基本情况和基本的方法,显示了怎样 ...
- 聊聊高并发(二十八)解析java.util.concurrent各个组件(十) 理解ReentrantReadWriteLock可重入读-写锁
这篇讲讲ReentrantReadWriteLock可重入读写锁,它不仅是读写锁的实现,而且支持可重入性. 聊聊高并发(十五)实现一个简单的读-写锁(共享-排他锁) 这篇讲了怎样模拟一个读写锁. 可重 ...
- Java基础-Java中的并法库之重入读写锁(ReentrantReadWriteLock)
Java基础-Java中的并法库之重入读写锁(ReentrantReadWriteLock) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在学习Java的之前,你可能已经听说过读 ...
- java 可重入读写锁 ReentrantReadWriteLock 详解
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt206 读写锁 ReadWriteLock读写锁维护了一对相关的锁,一个用于只 ...
- 018-并发编程-java.util.concurrent.locks之-ReentrantReadWriteLock可重入读写锁
一.概述 ReentrantLock是一个排他锁,同一时间只允许一个线程访问,而ReentrantReadWriteLock允许多个读线程同时访问,但不允许写线程和读线程.写线程和写线程同时访问.相对 ...
- 23、Java并发性和多线程-重入锁死
以下内容转自http://ifeve.com/reentrance-lockout/: 重入锁死与死锁和嵌套管程锁死非常相似.锁和读写锁两篇文章中都有涉及到重入锁死的问题. 当一个线程重新获取锁,读写 ...
- Java并发编程 ReentrantLock 源码分析
ReentrantLock 一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大. 这个类主要基于AQS(Abst ...
- 可重入读写锁ReentrantReadWriteLock基本原理分析
前言 本篇适用于了解ReentrantLock或ReentrantReadWriteLock的使用,但想要进一步了解原理的读者.见于之前的分析都是借鉴大量的JDK源码,这次以流程图的形式代替源码,希望 ...
随机推荐
- java后端使用token处理表单重复提交
保证接口幂等性,表单重复提交 前台解决方案:提交后按钮禁用.置灰.页面出现遮罩后台解决方案: 使用token,每个token只能使用一次1.在调用接口之前生成对应的Token,存放至redis 2 ...
- Spark学习摘记 —— RDD转化操作API归纳
本文参考 在阅读了<Spark快速大数据分析>动物书后,大概了解到了spark常用的api,不过书中并没有给予所有api具体的示例,而且现在spark的最新版本已经上升到了2.4.5,动物 ...
- 滑动窗口法——Leetcode例题
滑动窗口法--Leetcode例题(连更未完结) 1. 方法简介 滑动窗口法可以理解为一种特殊的双指针法,通常用来解决数组和字符串连续几个元素满足特殊性质问题(对于字符串来说就是子串).滑动窗口法的显 ...
- Python学习--21天Python基础学习之旅(Day03、Day04)
关于缩进问题,缩进几个空格都不影响程序解释(不会报错什么的),但一般缩进四个空格是为了可读性和规范. Day03: Chapter 5 1.if语句 1.1条件测试:值为True或False的表达式成 ...
- 雅虎WEB前端网站优化—34条军规
Yslow工具 1.Minimize HTTP Requests 减少HTTP请求 图片.css.script.flash等等这些都会增加http请求数,减少这些元素的数量就能减少响应时间.把多个JS ...
- C语言常用字符串函数
string.h头文件中常用的函数 C 库函数 - strcat() char *strcat(char *dest, const char *src) 把 src 所指向的字符串追加到 dest 所 ...
- react开发教程(六)React与DOM
ReactDOM findeDOMNode 语法:DOMElement findDOMNode(ReactComponent component)描述:获取改组件实例相对应的DOM节点 案例: imp ...
- RedisDesktopManager 连接不上远程 Redis
1.首先确保远程redis-server已经启用: 2.连接不到可能的原因: redis3.2以上版本默认开启保护模式,不允许外网访问,需要修改redis.conf文件 3.redis.conf文件需 ...
- 【uniapp 开发】日期工具类 -- DateUtil
日期格式转毫秒值 var time = '2019-08-08 12:09:34'; var time222 = time.replace("-", "/"). ...
- 【Python】Windows微信清理工具v.3.0.2
Windows微信清理工具v.3.0.2 更新内容: 1.清理完成时可显示删除了哪些文件. 软件截图: 所有版本及源码下载链接: 百度网盘:https://pan.baidu.com/s/1OSIpv ...