ReadWriteLock 读写之间互斥吗?我竟然答不上来。。

简介: ReadWriteLock 读写之间互斥吗?我竟然答不上来。。

开发中遇到并发的问题一般会用到锁,Synchronized存在明显的一个性能问题就是读与读之间互斥;ReadWriteLock是JDK5中提供的读写分离锁。读写分离锁可以有效地帮助减少锁竞争,以提升系统的性能。


ReadWriteLock管理一组锁,一个是只读的锁,一个是写锁。 Java并发库中ReetrantReadWriteLock实现了ReadWriteLock接口并添加了可重入的特性。


而读写锁ReentrantReadWriteLock:读读共享,读写互斥,写写互斥;读写锁维护了一对锁,一个读锁,一个写锁,通过分离读锁和写锁,使得并发性相比一般的排他锁有了很大提升。在读多写少的情况下,读写锁能够提供比排他锁更好的并发性和吞吐量。

image.png

从源码中可以看出,读写锁中同样依赖队列同步器Sync(AQS)实现同步功能,而读写状态就是其同步器的同步状态。下面从例子中来说明:读读共享,读写互斥,写写互斥。


代码如下:

public class ReentrantWriteReadLockTest {
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    ReadLock readLock = lock.readLock();
    WriteLock writeLock = lock.writeLock();
    public void read(){
        try {
            readLock.lock();
            System.out.println("线程"+Thread.currentThread().getName()+"进入。。。");
            Thread.sleep(3000);
            System.out.println("线程"+Thread.currentThread().getName()+"退出。。。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            readLock.unlock();
        }
    }
    public void write(){
        try {
            writeLock.lock();
            System.out.println("线程"+Thread.currentThread().getName()+"进入。。。");
            Thread.sleep(3000);
            System.out.println("线程"+Thread.currentThread().getName()+"退出。。。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            writeLock.unlock();
        }
    }
    public static void main(String[] args) {
        final ReentrantWriteReadLockTest wr = new ReentrantWriteReadLockTest();
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                wr.read();
            }
        }, "t1");
        Thread t2 = new Thread(new Runnable() {
            public void run() {
                wr.read();
            }
        }, "t2");
        Thread t3 = new Thread(new Runnable() {
            public void run() {
                wr.write();
            }
        }, "t3");
        Thread t4 = new Thread(new Runnable() {
            public void run() {
                wr.write();
            }
        }, "t4");
        t1.start();
        t2.start();
        //t3.start();
        //t4.start();
    }
}

当我们启动线程t1和t2时,结果如下:

image.png

线程t1和t2可以同时进入,说明了读读共享!


当我们启动线程t2和t3时,结果如下:

image.png

一个线程必须等待另一个线程退出,才能进入,说明了读写互斥!


当我们启动线程t3和t4时,结果如下:

image.png

一个线程必须等待另一个线程退出,才能进入,说明了写写互斥!


相关文章
|
资源调度 搜索推荐 Shell
使用VitePress静态网站生成器创建组件库文档网站并部署到GitHub
本文介绍了如何使用 Vue3、TypeScript 和 Vite 开发组件库并将其发布到 npm。文章详细描述了安装依赖、配置项目、创建文档网站以及编写组件文档的步骤。通过使用 VitePress,可以轻松搭建组件库的文档站点,并实现 Algolia 搜索功能。此外,还提供了自动化脚本用于部署静态网站至 GitHub 以及发布组件库到 npm。最后,展示了完整的目录结构和网站效果。
575 1
使用VitePress静态网站生成器创建组件库文档网站并部署到GitHub
|
机器学习/深度学习 搜索推荐 算法
【手撕排序算法1:插入排序与希尔排序】
【手撕排序算法1:插入排序与希尔排序】
|
弹性计算 Kubernetes Java
在本地 IDE 中快捷执行远程服务器命令 Command
Cloud Toolkit 新版本发布,允许开发者在本地 IDE 中快捷执行远程服务器命令 Command。
1472 72
|
JavaScript Shell
eventBus和$route.push.query同时用解决eventBus持久化问题,和跨组件引起的路由传参监听不到没变化的问题
eventBus和$route.push.query同时用解决eventBus持久化问题,和跨组件引起的路由传参监听不到没变化的问题
109 0
|
安全 Java 测试技术
Intellij IDEA基于Springboot的远程调试
Intellij IDEA基于Springboot的远程调试
748 0
Intellij IDEA基于Springboot的远程调试
|
搜索推荐 JavaScript API
vue2的$refs在vue3组合式API中的替代方法
如果你有过vue2的项目开发经验,那么对$refs就很熟悉了。由于vue3的断崖式的升级,在vue3中如何使用$refs呢?想必有遇到过类似的问题,我也有一样的疑惑。通过搜索引擎和github,基本掌握如何使用$refs。在vue3中使用组合式API的函数ref来代替静态或者动态html元素的应用。
1153 0
vue2的$refs在vue3组合式API中的替代方法
|
SQL 存储 缓存
《软件测试技术实战 设计、工具及管理》联载-12
《软件测试技术实战 设计、工具及管理》联载-12
157 0
|
Kubernetes 前端开发 持续交付
自动化集成:Kubernetes容器引擎详解
Kubernetes简称K8S,是一个开源的分布式的容器编排引擎,用来对容器化应用进行自动化部署和管理,让部署容器化的应用简单并且高效,支持自动化部署、大规模可伸缩、应用容器化管理。
633 0
自动化集成:Kubernetes容器引擎详解
|
Python
Python进阶——修改闭包内使用的外部变量
修改闭包内使用的外部变量
303 0
|
SQL 索引
开发指南—DAL语句—CHECK GLOBAL INDEX
您可以使用CHECK GLOBAL INDEX语句检查主表和索引表的数据是否完全一致,并修订不一致的数据。