Java多线程中读写锁ReadWriteLock的使用

该博客转载自lavimerJava多线程中读写锁ReadWriteLock的使用

1. 概念

读写锁分为读锁和写锁,多个读锁之间是不需要互斥的(读操作不会改变数据,如果上了锁,反而会影响效率),写锁和写锁之间需要互斥,也就是说,如果只是读数据,就可以多个线程同时读,但是如果你要写数据,就必须互斥,使得同一时刻只有一个线程在操作。

2. 案例

2.1 三线程读数据,三线程写数据

package com.tao.leanrn.thread.lock;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; /**
* @ClassName ReadWrite
* @Descriiption 读写锁
* @Author yanjiantao
* @Date 2019/8/21 10:42
**/
public class ReadWrite { /**
* 共享数据
*/
private int data = 0; /**
* 读写锁
*/
private ReadWriteLock lock = new ReentrantReadWriteLock(); public void get() { // 上读锁
lock.readLock().lock(); try {
System.out.println(Thread.currentThread().getName() + "----->读锁开始执行...");
Thread.sleep((long)(Math.random() * 10));
System.out.println(Thread.currentThread().getName() + "----->读锁得到数据data=" + data);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放锁
lock.readLock().unlock();
}
} public void set() { // 上写锁
lock.writeLock().lock(); try {
System.out.println(Thread.currentThread().getName() + "----->写锁开始执行...");
Thread.sleep((long)(Math.random() * 10));
data++;
System.out.println(Thread.currentThread().getName() + "----->写锁得到数据data=" + data);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放写锁
lock.writeLock().unlock();
} }
} /**
* 测试类
*/
class Main{ public static void main(String[] args) {
ReadWrite readWrite = new ReadWrite();
// 创建100个读写线程
for (int i = 0; i < 100; i++) {
new Thread(() -> {
readWrite.get();
}).start(); new Thread(() -> {
readWrite.set();
}).start();
}
} }

程序运行结果

2.2 模拟Hibernate缓存

public class HibernateCache {

	/* 定义一个Map来模拟缓存 */
private Map<String, Object> cache = new HashMap<String, Object>(); /* 创建一个读写锁 */
private ReadWriteLock rwLock = new ReentrantReadWriteLock(); /**
* 模拟Hibernate缓存
* @param key
* @return
*/
private Object getData(String key) { /* 上读锁 */
rwLock.readLock().lock();
/* 定义从缓存中读取的对象 */
Object value = null; try {
/* 从缓存中读取数据 */
value = cache.get(key); if (value == null) {
/* 如果缓存中没有数据,我们就把读锁关闭,直接上写锁【让一个线程去数据库中取数据】 */
rwLock.readLock().unlock();
/* 上写锁 */
rwLock.writeLock().lock(); try {
/* 上了写锁之后再判断一次【我们只让一个线程去数据库中取值即可,当第二个线程过来的时候,发现value不为空了就去缓存中取值】 */
if (value == null) {
/* 模拟去数据库中取值 */
value = "hello";
}
} finally {
/* 写完之后把写锁关闭 */
rwLock.writeLock().unlock();
}
/* 缓存中已经有了数据,我们再把已经 关闭的读锁打开 */
rwLock.readLock().lock();
}
} finally {
/* 最后把读锁也关闭 */
rwLock.readLock().unlock();
} return value;
} }

【转】-java多线程读写锁ReadWriteLock的更多相关文章

  1. java多线程-读写锁原理

    Java5 在 java.util.concurrent 包中已经包含了读写锁.尽管如此,我们还是应该了解其实现背后的原理. 读/写锁的 Java 实现(Read / Write Lock Java ...

  2. java多线程-读写锁

    Java5 在 java.util.concurrent 包中已经包含了读写锁.尽管如此,我们还是应该了解其实现背后的原理. 读/写锁的 Java 实现(Read / Write Lock Java ...

  3. 多线程编程_读写锁ReadWriteLock

    Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象.两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象. 读写锁:分为读 ...

  4. C# 多线程编程之锁的使用【互斥锁(lock)和读写锁(ReadWriteLock)】

    多线程编程之锁的使用[互斥锁(lock)和读写锁(ReadWriteLock)] http://blog.csdn.net/sqqyq/article/details/18651335 多线程程序写日 ...

  5. Java 读写锁 ReadWriteLock 原理与应用场景详解

    Java并发编程提供了读写锁,主要用于读多写少的场景,今天我就重点来讲解读写锁的底层实现原理@mikechen 什么是读写锁? 读写锁并不是JAVA所特有的读写锁(Readers-Writer Loc ...

  6. 线程中的读写锁ReadWriteLock

    Lock锁还有两个非常强大的类 ReadWriteLock接口实现类ReentrantReadWriteLock(非常重要的锁) 想实现 读取的时候允许多线程并发访问,写入的时候不允许. 这种效果.. ...

  7. 【漫画】互斥锁ReentrantLock不好用?试试读写锁ReadWriteLock

    ReentrantLock完美实现了互斥,完美解决了并发问题.但是却意外发现它对于读多写少的场景效率实在不行.此时ReentrantReadWriteLock来救场了!一种适用于读多写少场景的锁,可以 ...

  8. 读写锁ReadWriteLock

    为了提高性能,Java提供了读写锁,在读的地方使用读锁,在写的地方使用写锁,灵活控制,如果没有写锁的情况下,读是无阻塞的,在一定程度上提高了程序的执行效率. Java中读写锁有个接口java.util ...

  9. 【漫画】读写锁ReadWriteLock还是不够快?再试试StampedLock!

    本文来源于公众号[胖滚猪学编程] 转载请注明出处! 在互斥锁ReentrantLock不好用?试试读写锁ReadWriteLock一文中,我们对比了互斥锁ReentrantLock和读写锁ReadWr ...

  10. 读-写锁 ReadWriteLock & 线程八锁

    读-写锁 ReadWriteLock: ①ReadWriteLock 维护了一对相关的锁,一个用于只读操作, 另一个用于写入操作. 只要没有 writer,读取锁可以由 多个 reader 线程同时保 ...

随机推荐

  1. 谈谈笔者是怎么拿到HFish社区活动仅有的500京东E卡

    前言 早在2022年5月18日的时候,由于HFish官方文档的nginx配置文件问题,官方文档的nginx配置存在多处错误.在HFish的社区群里为群友解答如何使用nginx进行反向代理以及提供能供正 ...

  2. 定制Django的Tag和Filter(二)

    配置 (1)最常见的放置自定义Tag和Filter的地方是在Django的app下.当一个app被添加到settings.py的INSTALLED_APPS 后,任何在它下面的合法位置将自动的可在te ...

  3. FastAPI与MongoDB Change Stream的实时数据交响曲

    title: FastAPI与MongoDB Change Stream的实时数据交响曲 date: 2025/05/25 13:04:40 updated: 2025/05/25 13:04:40 ...

  4. post 报头注入

    1.user-agent 注入: 使用情况:万能密码无法绕过安全验证,用户名无法注入,通过查看源代码分析执行的动作. bp抓包修改user_agent的数据如下 User-Agent: ' or ud ...

  5. redis-cli 使用lua脚本笔记

    前言 众所周知,redis可以执行lua脚本,至于为什么要用lua脚本来操作redis,自行百度咯 先来讲一下最简单的方式, 关于如何在java springboot里用lua脚本,请查看我另一篇文章 ...

  6. 03 - LayoutPanels例子 - SimpleInkCanvas

    C# maui暂时没有官方支持InkCanvas,但是不影响,自己实现一个就行了.目前支持,画图,选择,移动和删除.同时支持自定义橡皮擦形状,也支持绑定自定义的形状列表. 实现一个Converter类 ...

  7. 数栈技术分享:解读MySQL执行计划的type列和extra列

    一.解读type 执行计划的type表示访问数据类型,有很多种访问类型. 1.system表示这一步只返回一行数据,如果这一步的执行对象是一个驱动表或者主表,那么被驱动表或者子查询只是被访问一次. 2 ...

  8. ATM2.0模块版

    ATM项目开发 (1)在主程序文件中创建程序入口 (2)在核心代码文件(视图层)搭建程序框架 (3)进行代码功能分配 - ATM 项目根目录 - README.md 项目说明书 - start.py ...

  9. 真正的生产力来了!Docker迁移部署两步搞定!

    前言 最近遇到了需要部署一套比较复杂的应用场景,刚好这套应用我在其他服务器部署过,为了节省折腾的时间,我打算直接把服务器上已有的搬过去. PS:没想到这个过程比从头开始来耗费时间 好在是把一键迁移的脚 ...

  10. C# datagridView 表格渲染变色 ( 动态改变表格值) 绘制时改变表格值

    private void DGV_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)        {           ...