【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源码,这次以流程图的形式代替源码,希望 ...
随机推荐
- 学习Kvm(五)
KVM(一)搭建部署与概述 一,KVM概述 1.1 虚拟化概述 在计算机技术中,虚拟化意味着创建设备或资源的虚拟版本,如服务器,存储设备,网络或者操作系统等等 [x] 虚拟化技术分类: 系统虚拟化(我 ...
- 4.RDD操作
目录 一. RDD创建 从本地文件系统中加载数据创建RDD 从HDFS加载数据创建RDD 通过并行集合(列表)创建RDD 二. RDD操作 转换操作 filter(func) map(func) fl ...
- C语言之常量(知识点4)
一.常量(概念) ①用标识符代表常量 ②一般用大写字母表示 二.定义格式 #define 符号常量 常量 三.案例 #define PI 40; #define PRICE 30; 四.注意 ①其值在 ...
- SQL数据库之设置查询出来数据为默认值
-- 如果工资为null,按0处理 -- 函数: ifnull(字段, 默认值) : 如果指定字段的内容是null, 就按默认值处理 select name, ifnull(salary, 0) fr ...
- c++ 虚函数多态、纯虚函数、虚函数表指针、虚基类表指针详解
静态多态.动态多态 静态多态:程序在编译阶段就可以确定调用哪个函数.这种情况叫做静态多态.比如重载,编译器根据传递给函数的参数和函数名决定具体要使用哪一个函数.动态多态:在运行期间才可以确定最终调用的 ...
- python-图的字典表示
图的字典表示.输入多行字符串,每行表示一个顶点和该顶点相连的边及长度,输出顶点数,边数,边的总长度.比如上图0点表示:{'O':{'A':2,'B':5,'C':4}}.用eval函数处理输入,eva ...
- AS的不同布局
AndroidStudio里面支持的布局有挺多种的,但是最最重要的是RelativeLayout(相对布局)和LinearLayout(线性布局),熟练掌握这两种布局也非常够用了,当然还有FrameL ...
- js 生成 pdf 文件
话不多说好吧, 直接上demo图: 直接上代码好吧:(要引入的两个js 链接我放最后) <!DOCTYPE html> <html> <head> <met ...
- Python入门-pip模块管理工具
安装 # 在线安装 pip install <包名> 安装后,该模块文件会在安装python环境目录:lib/packages目录下 # 安装本地安装包 pip install <目 ...
- MySQL性能优化的5个维度
面试官如果问你:你会从哪些维度进行MySQL性能优化?你会怎么回答? 所谓的性能优化,一般针对的是MySQL查询的优化.既然是优化查询,我们自然要先知道查询操作要经过哪些环节,然后思考可以在哪些环节进 ...