对于 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 信号量机制。“写锁” 保证临界资源能被唯一占用,解决了 “写写同步问题”。而当且仅当 “读锁” 队列为空时,“写锁” 才能被获取。且 “写锁” 和 “读锁” 在同一时刻不能同时被持有,解决了 “读写同步问题”,且它还能保证能够 “同时读” 的特性。

最新文章

  1. 委托、回调 Lambda表达式书写方式
  2. xampp3.2下mysql中文乱码终极解决方案
  3. sap去除后缀0方法
  4. JS判断登陆端是PC还是手机
  5. struts2获取web元素的方式和方法
  6. SQL server 2008数据库的备份与还原(转)
  7. Linux MTD系统剖析【转】
  8. Golang 图片上绘制文字
  9. Windows系统下的adb 配置
  10. Linux下Tomcat的安装配置 去掉应用名称
  11. 1854: [Scoi2010]游戏
  12. video视频铺满
  13. IntelliJ IDEA 左侧列表设置忽略文件格式
  14. 高效的CSS代码(1)
  15. python_爬校花图片
  16. 【最小生成树+子集枚举】Uva1151 Buy or Build
  17. 【转】iOS开发笔记--识别单击还是双击
  18. linux全部替换命令学习
  19. 1、mysql初识
  20. Elasticsearch学习之图解Elasticsearch中的_source、_all、store和index属性

热门文章

  1. el-table的花样需求---表格加图片、加音频、加序号、多级动态表头
  2. PuTTY通过SSH连接上Ubuntu20.04
  3. fiddler修改请求参数
  4. python基础001----Python+pycharm环境搭建
  5. 如何 SSH 到 Linux 服务器里的特定目录及执行命令?
  6. WeChair项目Alpha冲刺(7/10)
  7. 客户端软件GUI开发技术漫谈:原生与跨平台解决方案分析
  8. 傻瓜式教学--win10 + frp + rdpwrap + 阿里云服务器 --实现win10 多用户同时远程登录内网机
  9. MQ消息队列(1)—— 概念和使用场景
  10. 2、尚硅谷_SSM高级整合_创建Maven项目.avi