【【java并发编程】ReentrantLock 可重入读写锁】
文章图片
[TOC]
一、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将锁分为读锁和写锁,只要没有线程持有写锁的情况下,读锁可以由多个线程同时持有。
- 读锁-如果没有线程获取或请求写锁,那么多个线程可以获取读锁
- 写锁-如果没有线程在读或写,那么只有一个线程可以获得写锁
下面我们用一个简单的例子,来解读一下如何应用读写锁。
public class TestReadWriteLock {
//可以同时执行3个线程任务的线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
//读写目标,写线程放入数据到map,读线程从map读取数据
Map 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微服务从青铜到王者》
推荐阅读
- 笔记|基于JavaWeb的简单博客系统
- 笔记|JavaWeb项目【实现基础博客系统】
- 算法|三维重建——相机几何参数标定
- java|2022年最新Java 后端开发面试总结,没有之一
- java|【java面试合集】--更新中
- 剑指office(Java版)|面试题22(链表中环的入口节点(Java版))
- java|Java使用jsoup爬取网页数据
- 面试|SpringBoot中使用WebSocket的方法
- ibatis|ibatis 数据增删改查一日一表的情况