ReadWriteLock锁的应用
对于 Lock 锁来说,如果要实现 “一写多读” 的并发状态(即允许同时读,不允许同时写),需要对 “写操作” 加锁,对 “读操作” 不作要求即可。但是如果对于 “读” 操作下,有 “写操作” 接入的话,对于当前的 “读操作” 可能会产生 “幻读” 的现象。所以对于要实现 “一写多读” 的情况下,应推荐使用 ReadWriteLock 锁。
ReadWriteLock 是与 Lock 平级的一个 JUC 包下的接口
它唯一的实现类是 ReentrantReadWriteLock 类,一个 ReentrantReadWriteLock 对象维护了一对关联的locks ,一个用于只读操作,一个用于写入。
简单来说:
- 它维护了两个锁,一个叫 “读锁”,一个叫 “写锁”。
- 为了允许 “一写多读” 的操作,按理上,“写锁” 一旦上锁,不能再被获取;而为了保证能同时读数据,“读锁” 若上锁,想获取 “读锁” 的线程仍然可以执行读操作,而为了防止 “读操作” 执行时有 “写操作” 的接入,应该要防止 “写锁” 被获取。
下面通过 4 个不同顺序的读写实例来演示一遍(代码贴在最后面)
1、一个线程已获取 “读锁” 状态下,另一个线程尝试获取 “写锁” 。
在 “读锁” 被获取的情况下,“写锁” 不能被获取。(即便是在多个线程都获取 “读锁”,“写锁” 必须在所有 “读操作” 结束后才能被获取,可自行测试)
2、一个线程已获取 “写锁” 状态下,另一个线程尝试获取 “读锁” 。
在 “写锁” 被获取的情况下,“读锁” 不能被获取。
3、一个线程已获取 “读锁” 状态下,另一个线程尝试获取 “读锁” 。
在 “读锁” 被获取的情况下,“读锁” 还能被获取,类似于 Semaphore 辅助类。
4、一个线程已获取 “写锁” 状态下,另一个线程尝试获取 “写锁” 。
在 “写锁” 被获取的情况下,“写锁” 不能被获取。
总代码
package ReadWriteLock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockDemo {
private final static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public static void main(String[] args) throws InterruptedException {
writeAndWriteTest();
}
public static void readAndWriteTst() throws InterruptedException {
//第一个线程先获取写锁,另一个线程再获取读锁
new Thread(() -> {
readWriteLock.writeLock().lock();
System.out.println("写锁已获取");
try {
Thread.sleep(8000);
readWriteLock.writeLock().unlock();
System.out.println("已关闭写锁");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Thread.sleep(3000);
System.out.println("另一个线程尝试获取读锁");
new Thread(() -> {
readWriteLock.readLock().lock();
System.out.println("另一个线程的读锁已获取");
}).start();
}
public static void writeAndReadTest() throws InterruptedException {
//第一个线程先获取读锁,另一个线程再获取写锁
new Thread(() -> {
readWriteLock.readLock().lock();
System.out.println("读锁已获取");
try {
Thread.sleep(8000);
readWriteLock.readLock().unlock();
System.out.println("已关闭读锁");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Thread.sleep(3000);
System.out.println("另一个线程尝试获取写锁");
new Thread(() -> {
readWriteLock.writeLock().lock();
System.out.println("另一个线程的写锁已获取");
}).start();
}
public static void readAndReadTest() throws InterruptedException {
//一个线程已获读锁,另一个线程再获取读锁
new Thread(() -> {
readWriteLock.readLock().lock();
System.out.println("读锁已获取");
try {
Thread.sleep(8000);
readWriteLock.readLock().unlock();
System.out.println("已关闭读锁");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Thread.sleep(3000);
System.out.println("另一个线程尝试获取读锁");
new Thread(() -> {
readWriteLock.readLock().lock();
System.out.println("另一个线程的读锁已获取");
}).start();
}
public static void writeAndWriteTest() throws InterruptedException {
//一个线程已获写锁,另一个线程再获取写锁
new Thread(() -> {
readWriteLock.writeLock().lock();
System.out.println("写锁已获取");
try {
Thread.sleep(8000);
readWriteLock.writeLock().unlock();
System.out.println("已关闭写锁");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Thread.sleep(3000);
System.out.println("另一个线程尝试获取写锁");
new Thread(() -> {
readWriteLock.writeLock().lock();
System.out.println("另一个线程的写锁已获取");
}).start();
}
}
> 总结
ReentrantReadWriteLock 中的写锁类似于 Lock 锁,而读锁类似于 Semaphore 信号量机制。“写锁” 保证临界资源能被唯一占用,解决了 “写写同步问题”。而当且仅当 “读锁” 队列为空时,“写锁” 才能被获取。且 “写锁” 和 “读锁” 在同一时刻不能同时被持有,解决了 “读写同步问题”,且它还能保证能够 “同时读” 的特性。
ReadWriteLock锁的应用的更多相关文章
- Java并发编程-各种锁
安全性和活跃度通常相互牵制.我们使用锁来保证线程安全,但是滥用锁可能引起锁顺序死锁.类似地,我们使用线程池和信号量来约束资源的使用, 但是缺不能知晓哪些管辖范围内的活动可能形成的资源死锁.Java应用 ...
- java 锁 Lock接口详解
一:java.util.concurrent.locks包下常用的类与接口(lock是jdk 1.5后新增的) (1)Lock和ReadWriteLock是两大锁的根接口,Lock代表实现类是Reen ...
- 【转】java并发编程系列之ReadWriteLock读写锁的使用
前面我们讲解了Lock的使用,下面我们来讲解一下ReadWriteLock锁的使用,顾明思义,读写锁在读的时候,上读锁,在写的时候,上写锁,这样就很巧妙的解决synchronized的一个性能问题:读 ...
- java并发编程实战:第十三章----显示锁
一.Lock与ReentrantLock Lock接口中定义了一种无条件.可轮询的.定时的以及可中断的锁获取操作,所有加锁和解锁的方法都是显式的. 1 public interfece Lock 2 ...
- cocurrent包 锁 Lock
20. 锁 Lock java.util.concurrent.locks.Lock 是一个类似于 synchronized 块的线程同步机制.但是 Lock 比 synchronized 块更加灵活 ...
- java并发编程(七)----(JUC)ReadWriteLock
前面我们已经分析过JUC包里面的Lock锁,ReentrantLock锁和semaphore信号量机制.Lock锁实现了比synchronized更灵活的锁机制,Reentrantlock是Lock的 ...
- StampedLock:一个并发编程中非常重要的票据锁
摘要:一起来聊聊这个在高并发环境下比ReadWriteLock更快的锁--StampedLock. 本文分享自华为云社区<[高并发]一文彻底理解并发编程中非常重要的票据锁--StampedLoc ...
- Java 并发工具包 java.util.concurrent 用户指南
1. java.util.concurrent - Java 并发工具包 Java 5 添加了一个新的包到 Java 平台,java.util.concurrent 包.这个包包含有一系列能够让 Ja ...
- Java并发编程-并发工具包(java.util.concurrent)使用指南(全)
1. java.util.concurrent - Java 并发工具包 Java 5 添加了一个新的包到 Java 平台,java.util.concurrent 包.这个包包含有一系列能够让 Ja ...
随机推荐
- const修饰this指针的用法
#include <iostream> #include <string> using namespace std; class Base { }; class Excepti ...
- deepin文件用途
Bin:二进制文件, 存放二进制文件Dev:存放外接设备,其中外接设备不能被直接使用需要挂载(启动设备)Etc:存放配置文件Home:家目录,出了root用户外的其他用户类似于Windows中的use ...
- 'ipconfig' 不是内部或外部命令,也不是可运行的程序 或批处理文件
今天在学习的时候需要找本地ip地址,可是在命令行窗口却显示 百度之后发现原来是环境变量没配置的问题(其实之前是ok的,但应该是anconda安装的时候点了那个一键设置环境变量搞得本地的path里的数据 ...
- 2020年最新78道JVM面试题总结(含答案解析和思维导图)
前言 关于JVM系列面试知识点总结了一个思维导图,分享给大家 1.java中会存在内存泄漏吗,请简单描述. 会.自己实现堆载的数据结构时有可能会出现内存泄露. 2.64 位 JVM 中,int 的长度 ...
- 微信小程序-页面跳转与参数传递
QQ讨论群:785071190 微信小程序页面跳转方式有很多种,可以像HTML中a标签一样添加标签进行跳转,也可以通过js中方法进行跳转. navigator标签跳转 <view class=& ...
- Flutter学习笔记(37)--动画曲线Curves 效果
如需转载,请注明出处:Flutter学习笔记(37)--动画曲线Curves 效果
- chromedp入门
chromedp入门 chromedp是什么? chromedp是go写的,支持Chrome DevTools Protocol 的一个驱动浏览器的库.并且它不需要依赖其他的外界服务(比如 Selen ...
- Maven全局配置文件settings.xml详解(转)
Maven全局配置文件settings.xml详解 目录 一.概要 1.settings.xml的作用2.settings.xml文件位置3.配置的优先级 二.settings.xml元素详解 1 ...
- 黎活明8天快速掌握android视频教程--23_网络通信之网络图片查看器
1.首先新建立一个java web项目的工程.使用的是myeclipe开发软件 图片的下载路径是http://192.168.1.103:8080/lihuoming_23/3.png 当前手机和电脑 ...
- Quartz.Net系列(九):Trigger之DailyTimeIntervalScheduleBuilder详解
1.介绍 中文意义就是每日时间间隔计划生成 2.API讲解 (1)WithInterval.WithIntervalInHours.WithIntervalInMinutes.WithInterval ...