java实现ReadWriteLock读写锁的示例

 更新时间:2024年09月25日 10:30:22   作者:草履虫·  
ReadWriteLock是Java并发包中的接口,定义了读锁和写锁,读锁允许多线程同时访问共享资源,而写锁则要求独占,这种机制适用于读多写少的场景,可以提高并发效率同时保证数据一致性,本文就来详细的介绍一下如何实现,感兴趣的可以了解一下

读写锁基本概念

ReadWriteLock是Java并发包中的一个接口,它定义了两种锁:读锁(Read Lock)和写锁(Write Lock),真正的实现类是ReentrantReadWriteLock。读锁允许多个线程同时读取共享资源,而写锁则要求独占资源,即当一个线程持有写锁时,其他线程不能获取读锁或写锁。

读写锁的作用

在进行共享资源的并发访问时,不论是使用synchronized还是使用重入锁ReentrantLock,一次都只允许一个线程访问共享资源,但是很多时候我们只是要读取共享资源,并不修改共享资源,多个线程同时读取共享资源并不会产生不一致问题,而且还能提高并发效率,对共享资源修改时就只让一个线程进入,又保证数据的一致性,这就是读写锁ReadWriteLock诞生的原因。读写锁分离是一种常见的锁思想。例如在一些数据库内,利用读锁让多个事务可以同时读某行数据,并且数据不会被修改,利用写锁保证只有一个事务可以修改某行数据,并且不会被其它事务读取到脏数据。

写锁:也叫作排他锁,如果数据有加写锁,就只有持有写锁的线程才能对数据进行操作,数据加持着写锁时,其他线程不能加写锁,也不能施加读锁。

读锁:也叫作共享锁,多个线程可以对同一个数据添加多个读锁,数据被加上读锁后就不能再被加上写锁。

读写锁的使用

使用ReadWriteLock实现读写控制示例:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class RWLock {
    public static final CountDownLatch countDownLatch = new CountDownLatch(10);
    public static final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    //获取读锁
    public static final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
    //获取写锁
    public static final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();

    public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        //8个线程模拟读操作
        for (int i = 0; i < 8; i++) {
            new Thread(() -> {
                readLock.lock();
                try {
                    Thread.sleep(1000); // 模拟读操作
                    countDownLatch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    readLock.unlock();
                }
            }).start();
        }
         //2个线程模拟写操作
        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                writeLock.lock();
                try {
                    Thread.sleep(2000); // 模拟写操作
                    countDownLatch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    writeLock.unlock();
                }
            }).start();
        }
        //等待所有操作完成
        countDownLatch.await();
        long end = System.currentTimeMillis();
        System.out.println("任务完成,耗时:" + (end - start));
    }
}
//任务完成,耗时:3081

使用ReentrantLock实现读写控制示例:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;

public class RWLock {
    public static final CountDownLatch countDownLatch = new CountDownLatch(10);
    public static final ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();

        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                lock.lock();
                try {
                    Thread.sleep(1000); // 模拟读操作
                    countDownLatch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }).start();
        }
        //等待所有操作完成
        countDownLatch.await();
        long end = System.currentTimeMillis();
        System.out.println("任务完成,耗时:" + (end - start));
    }
}
//任务完成,耗时:10155

以上两个示例中,使用ReadWriteLock实现的读写控制任务总耗时3秒左右,而使用ReentrantLock的实现的读写控制任务总耗时10秒左右,在这个例子中ReadWriteLock比ReentrantLock快了3倍多,这是否就意味着ReadWriteLock的性能就一定比ReentrantLock好呢?其实不是的,ReadWriteLock适用于读多写少的场景,如上面例子中使用了8个线程模拟读操作,2个线程模拟写操作就是读多写少的场景,在写操作密集的场景下ReadWriteLock的复杂性使它具有更大的锁开销。应该在不同的场景下选择合适的锁。

到此这篇关于java实现ReadWriteLock读写锁的示例的文章就介绍到这了,更多相关java ReadWriteLock读写锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java多线程实现之同步方法详解

    Java多线程实现之同步方法详解

    当多个线程同时访问共享资源时,可能会导致数据不一致等线程安全问题,Java提供了synchronized关键字来实现线程同步,确保同一时刻只有一个线程可以访问共享资源,下面就来介绍一下如何使用,感兴趣的可以了解一下
    2025-12-12
  • Java使用Thumbnailator库实现图片处理与压缩功能

    Java使用Thumbnailator库实现图片处理与压缩功能

    Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应用中的图片处理需求,本文给大家介绍Java使用Thumbnailator库实现图片处理与压缩功能,感兴趣的朋友一起看看吧
    2025-08-08
  • Java多线程Callable和Future接口区别

    Java多线程Callable和Future接口区别

    这篇文章主要介绍了Java多线程Callable和Future接口区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • 使用Spring Cache设置缓存条件操作

    使用Spring Cache设置缓存条件操作

    这篇文章主要介绍了使用Spring Cache设置缓存条件操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • SpringBoot项目作为文件服务器配置方式

    SpringBoot项目作为文件服务器配置方式

    本文介绍了使用Spring Boot和Kkfileview实现文件在线预览功能的配置过程,包括yml配置、webmvc配置、拦截器配置以及部署到服务器时的注意事项
    2025-12-12
  • SpringBoot整合Redis将对象写入redis的实现

    SpringBoot整合Redis将对象写入redis的实现

    本文主要介绍了SpringBoot整合Redis将对象写入redis的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • Java之SpringCloud nocos注册中心讲解

    Java之SpringCloud nocos注册中心讲解

    这篇文章主要介绍了Java之SpringCloud nocos注册中心讲解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • 使用Mock进行业务逻辑层Service测试详解

    使用Mock进行业务逻辑层Service测试详解

    这篇文章主要介绍了使用Mock进行业务逻辑层Service测试详解,mock是一种模拟对象的技术,用于在测试过程中替代真实的对象,通过mock,我们可以控制被模拟对象的行为和返回值,以便进行更加精确的测试,需要的朋友可以参考下
    2023-08-08
  • RabbitMq 常用命令和REST API详解

    RabbitMq 常用命令和REST API详解

    RabbitMQ管理命令涵盖服务启停、用户权限、虚拟主机、队列操作、消息管理及集群配置,包含创建/删除用户、设置角色、绑定交换机与队列、REST API数据查询等关键操作,需注意参数格式和角色唯一性限制,本文给大家介绍RabbitMq常用命令和REST API,感兴趣的朋友一起看看吧
    2025-07-07
  • JAVA实现图书管理系统项目

    JAVA实现图书管理系统项目

    相信每一个学生学编程的时候,应该都会写一个小项目——图书管理系统。为什么这么说呢?我认为一个学校的氛围很大一部分可以从图书馆的氛围看出来,而图书管理系统这个不大不小的项目,接触的多,也比较熟悉,不会有陌生感,能够练手,又有些难度,所以我的小项目也来了
    2021-10-10

最新评论