读写锁 ReadWriteLock 获取锁有哪些规则呢?

在没有读写锁之前,我们假设使用普通的 ReentrantLock,那么虽然我们保证了线程安全,但是也浪费了一定的资源,因为如果多个读操作同时进行,其实并没有线程安全问题,我们可以允许让多个读操作并行,以便提高程序效率。

但是写操作不是线程安全的,如果多个线程同时写,或者在写的同时进行读操作,便会造成线程安全问题。

我们的读写锁就解决了这样的问题,它设定了一套规则,既可以保证多个线程同时读的效率,同时又可以保证有写入操作时的线程安全。

整体思路是它有两把锁,第 1 把锁是写锁,获得写锁之后,既可以读数据又可以修改数据,而第 2 把锁是读锁,获得读锁之后,只能查看数据,不能修改数据。读锁可以被多个线程同时持有,所以多个线程可以同时查看数据。

在读的地方合理使用读锁,在写的地方合理使用写锁,灵活控制,可以提高程序的执行效率。

读写锁的获取规则

我们在使用读写锁时遵守下面的获取规则:

如果有一个线程已经占用了读锁,则此时其他线程如果要申请读锁,可以申请成功。

如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁,因为读写不能同时操作。

如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁,都必须等待之前的线程释放写锁,同样也因为读写不能同时,并且两个线程不应该同时写。

所以我们用一句话总结:要么是一个或多个线程同时有读锁,要么是一个线程有写锁,但是两者不会同时出现。

也可以总结为:读读共享、其他都互斥(写写互斥、读写互斥、写读互斥)。

使用案例
下面我们举个例子来应用读写锁,ReentrantReadWriteLock 是 ReadWriteLock 的实现类,最主要的有两个方法:readLock() 和 writeLock() 用来获取读锁和写锁。

/**
 * 描述:     演示读写锁用法
 */
public class ReadWriteLockDemo {

private static final ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(
            false);
    private static final ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock
            .readLock();
    private static final ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock
            .writeLock();

private static void read() {
        readLock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + "得到读锁,正在读取");
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println(Thread.currentThread().getName() + "释放读锁");
            readLock.unlock();
        }
    }

private static void write() {
        writeLock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + "得到写锁,正在写入");
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println(Thread.currentThread().getName() + "释放写锁");
            writeLock.unlock();
        }
    }

public static void main(String[] args) throws InterruptedException {
        new Thread(() -> read()).start();
        new Thread(() -> read()).start();
        new Thread(() -> write()).start();
        new Thread(() -> write()).start();
    }
}
程序的运行结果是:

复制代码
Thread-0得到读锁,正在读取
Thread-1得到读锁,正在读取
Thread-0释放读锁
Thread-1释放读锁
Thread-2得到写锁,正在写入
Thread-2释放写锁
Thread-3得到写锁,正在写入
Thread-3释放写锁
可以看出,读锁可以同时被多个线程获得,而写锁不能。

读写锁适用场合
最后我们来看下读写锁的适用场合,相比于 ReentrantLock 适用于一般场合,ReadWriteLock 适用于读多写少的情况,合理使用可以进一步提高并发效率。

引用:https://kaiwu.lagou.com/course/courseInfo.htm?courseId=16#/detail/pc?id=265

Java多线程学习十六:读写锁 ReadWriteLock 获取锁有哪些规则相关推荐

  1. Java并发原理抽丝剥茧,读写锁ReadWriteLock实现深入剖析

    跟着作者的65节课彻底搞懂Java并发原理专栏,一步步彻底搞懂Java并发原理. 作者简介:笔名seaboat,擅长工程算法.人工智能算法.自然语言处理.架构.分布式.高并发.大数据和搜索引擎等方面的 ...

  2. Java多线程学习十四:Lock 有哪几个常用方法?分别有什么用?

    Lock 接口是 Java 5 引入的,最常见的实现类是 ReentrantLock,可以起到"锁"的作用. Lock 和 synchronized 是两种最常见的锁,锁是一种工具 ...

  3. Java多线程学习十二: synchronized的工作原理 以及背后的“monitor 锁”

    我们研究下 synchronized 背后的 monitor 锁. 获取和释放 monitor 锁的时机 我们都知道,最简单的同步方式就是利用 synchronized 关键字来修饰代码块或者修饰一个 ...

  4. Java多线程学习十五:公平锁和非公平锁,为什么要“非公平”?

    什么是公平和非公平 公平锁 指的是按照线程请求的顺序,来分配锁: 非公平锁 指的是不完全按照请求的顺序,在一定情况下,可以允许插队.但需要注意这里的非公平并不是指完全的随机,不是说线程可以任意插队,而 ...

  5. java 集合读写同步_JAVA多线程学习十六 - 同步集合类的应用

    1.引言 在多线程的环境中,如果想要使用容器类,就需要注意所使用的容器类是否是线程安全的.在最早开始,人们一般都在使用同步容器(Vector,HashTable),其基本的原理,就是针对容器的每一个操 ...

  6. Java多线程学习十二:悲观锁和乐观锁的本质||

    悲观锁和乐观锁是从是否锁住资源的角度进行分类的. 悲观锁 悲观锁比较悲观,它认为如果不锁住这个资源,别的线程就会来争抢,就会造成数据结果错误,所以悲观锁为了确保结果的正确性,会在每次获取并修改数据时, ...

  7. Java多线程学习十九:JVM 对锁进行了哪些优化?

    JVM 对锁进行了哪些优化呢? 相比于 JDK 1.5,在 JDK 1.6 中 HotSopt 虚拟机对 synchronized 内置锁的性能进行了很多优化,包括自适应的自旋.锁消除.锁粗化.偏向锁 ...

  8. Java多线程学习十:线程池实现“线程复用”的原理

    线程复用原理 我们知道线程池会使用固定数量或可变数量的线程来执行任务,但无论是固定数量或可变数量的线程,其线程数量都远远小于任务数量,面对这种情况线程池可以通过线程复用让同一个线程去执行不同的任务,那 ...

  9. Java之读写锁ReadWriteLock实现

    一.为什么需要读写锁? 与传统锁不同的是读写锁的规则是可以共享读,但只能一个写,总结起来为:读读不互斥,读写互斥,写写互斥,而一般的独占锁是:读读互斥,读写互斥,写写互斥,而场景中往往读远远大于写,读 ...

最新文章

  1. WinAPI: SetRect 及初始化矩形的几种办法
  2. Matlab循环读取txt文件并对其中数据进行计算最后导出为excel
  3. 如何测试大端存储和小端存储
  4. html css 画五角星,纯 CSS3 绘制图形(心形、五角星、六边形等)
  5. Visual-FoxPro常用命令word版
  6. SSM之Mybatis框架
  7. 华中农业大学C语言实验5答案,物理实验报告册(上册)-华中农业大学实验.pdf
  8. 联想台式机usb驱动_windows安装系列教程—驱动安装
  9. SM2算法全套(基于GMSSL)
  10. 打造前端 Deepin Linux 工作环境——安装 nodejs 环境,git 版本管理
  11. osgearth加载倾斜摄影数据
  12. 利用tftp服务器进行IOS备份升级
  13. 把你的面子撕下来扔到地上,狠狠踹几脚!
  14. centos 6.7 mysql密码忘记_CentOS 7安装MySQL5.7以及忘记root密码怎么办
  15. HttpRequest 介绍
  16. 美度舵手系列多功能计时腕表伴你行走世界
  17. 启动3dMax时一直停留在启动屏幕并显示文本“starting 3ds Max…”怎么办?
  18. JS获取日期(年/月/日/时/分/秒)以及完整格式转化(补0)
  19. 【大学计算机技术】第三、四章 测试4
  20. 电脑里文件名称怎么快速重命名

热门文章

  1. Apple Watch要用上microLED显示屏了 最早明年...
  2. 苹果在中国设立首个App设计开发加速器
  3. 华为否认降低手机产量传闻:全球生产水平正常 无明显调整
  4. 华为的接班人要具备哪些能力?任正非这样说...
  5. 苹果卖这么贵都怪她?苹果零售部门主管将离职 曾是奢侈品巨头掌门人
  6. 贝叶斯网的R实现( Bayesian networks in R)bnlearn(2)
  7. 服务器集群名称是否可修改,云服务器可以集群吗
  8. 95-38-045-Buffer-UnpooledByteBuf
  9. 【Elasticsearch】运行 400 多个节点的 Elasticsearch 集群
  10. 【Elasticsearch】es IK分词器的安装