Java多线程中有很多的锁机制,他们都有各自的应用场景,例如今天我说的这种锁机制:读写锁

读写锁,见名知意,主要可以进行两种操作,读和写操作,他们之间结合使用起来又是各不相同的。比如多个线程之间可以同时读,但不可以同时写,也不可以一边读一边写,有点类似于数据库中的共享锁以及排它锁,下面我具体事例演示:

需要注意的是,不管是进行读操作还是写操作,一定要成对去调用方法,就是开启锁后一定要关闭,且为了保险起见,关闭最好要写在finally语句块中去。
另外,我们在声明对象时,有两种方式(有参数和无参数),若为true则为公平机制,默认为false,不写也为false

简单举例演示

package day_12_27;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; /**
* @author soberw
* @Classname ReadWriteLockTest
* @Description ReadWriteLock的测试
* @Date 2021-12-27 10:10
*/
public class ReadWriteLockTest {
public static void main(String[] args) {
var rwl = new RWL();
//情况一:
new Thread(() -> rwl.write(100), "A").start();
//情况二:
// new Thread(() -> rwl.write(99), "AA").start();
// new Thread(() -> rwl.write(88), "AAA").start(); for (int i = 0; i < 20; i++) {
new Thread(rwl::read, "B" + i).start();
}
}
} class RWL {
//可以传参,若为true则为公平锁,默认为false,不写也为false
private ReadWriteLock rwl = new ReentrantReadWriteLock();
public int number; void write(int number) {
rwl.writeLock().lock();
try {
this.number = number;
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + ":start--" + number);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
rwl.writeLock().unlock();
}
} void read() {
rwl.readLock().lock();
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + ":" + number);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
rwl.readLock().unlock();
}
}
}

先分析代码,写线程两秒后写入一个线程“A”,然后开启20个读线程都去读数据,结果:

在写的时候,会停顿两秒,因为我加了sleep(),但是我在读的时候也加了阻塞,却发现20个进程还是同时执行了,这就说明多个进程之间可以同时读,且读写不能同时进行,当线程写的时候,其他所有的读线程都要等着

下面打开情况二,多个线程都进行写操作:

发现会一个一个执行,间隔两秒,并不会像读操作一样,同时进行,这说明写不能同时进行

应用场景举例

那么在实际开发中,常用这种锁机制来完成缓存系统的操作。所谓缓存系统,举个例子,就比如用户要读取某个数据的时候,我不直接去向数据库请求,而是先看我内部有没有这个数据,如果有就直接返回,如果没有,就从数据库中查找这个数,查到后将这个数据存入我内部存储器中,下次再有人来要这个数据,我就直接返回这个数不用再到数据库中找了,这就大大的避免了频繁的访问数据库。下面我就书写代码模拟这一过程:

package day_12_27;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; /**
* @author soberw
* @Classname ExerData
* @Description 模拟缓存系统
* @Date 2021-12-27 20:02
*/
public class ExerData {
private static ReadWriteLock rwLock = new ReentrantReadWriteLock(); private static Map<String, Object> map = new HashMap<String, Object>(); public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
final String key = i + "";
new Thread(new Runnable() { @Override
public void run() {
for (int i1 = 0; i1 < 5; i1++) { System.out.println(Thread.currentThread().getName() + " read data: " + getData(key)); }
}
}).start();
}
} public static Object getData(String key) {
rwLock.readLock().lock();
Object value = null;
try {
value = map.get(key);
if (value == null) {
rwLock.readLock().unlock();
rwLock.writeLock().lock(); try {
if (value == null) {
// 此处在实际应用中,就是从数据库中查找数据,放入缓存中
value = Thread.currentThread().getName() + new Date();
} } finally {
rwLock.writeLock().unlock();
}
rwLock.readLock().lock();
} } finally {
rwLock.readLock().unlock();
} return value;
} }

运行结果:

最新文章

  1. 读书笔记:《HTML5开发手册》
  2. iOS各种调试技巧豪华套餐
  3. android服务之MP3播放(2)
  4. Mean Shift Tracking: 2000-2012回顾 (新论文更新)
  5. rds材资收集
  6. 如何用nodejs写入mysql 的blob格式的数据
  7. 研究一家公司 z
  8. Linux运行级别简介
  9. bat脚本:Java一键编译(Javac java)
  10. 干货,不小心执行了rm -f,除了跑路,如何恢复?
  11. unicorn与nginx通讯--[ruby unix socket]
  12. SQLServer之修改标量值函数
  13. [PHP]PHP rpc框架hprose测试
  14. linux下设置mysql5.7数据库远程访问
  15. 牛客训练赛25-A-因数个数
  16. 清理SharePoint 2013 安装配置环境
  17. 深入浅出的理解框架(Struts2、Hibernate、Spring)与 MVC 设计模式
  18. Notes中几个处理多值域的通用函数
  19. python中的print()、str()和repr()的区别
  20. NOSQL -- Mongodb的简单操作与使用(wins)

热门文章

  1. css基础-2 div布局
  2. linux(CentOS7) 之 jdk1.8 下载及安装
  3. CSS相关知识及入门
  4. test_5 排序‘+’、‘-’
  5. 【Java】IntelliJ IDEA 快捷键
  6. RHCSA 第一天
  7. CMake与OpenMP
  8. 【Android】安卓四大组件之Activity(二)
  9. Ajax_axios发送ajax请求
  10. 使用AJAX请求调用出现HTTPS协议错误问题