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读写锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springboot3.4和mybatis plus的版本问题的解决

    springboot3.4和mybatis plus的版本问题的解决

    本文主要介绍了springboot3.4和mybatis plus的版本问题的解决,主要由于Spring Boot 3.4与MyBatis-Plus版本不匹配导致分页功能问题,下面就来解决这个问题,感兴趣的可以了解一下
    2025-03-03
  • Java double类型比较大小详解

    Java double类型比较大小详解

    这篇文章主要介绍了Java double类型比较大小,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • Java二维数组查找功能代码实现

    Java二维数组查找功能代码实现

    这篇文章主要介绍了Java二维数组查找功能代码实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • Java多线程中ReentrantLock与Condition详解

    Java多线程中ReentrantLock与Condition详解

    这篇文章主要介绍了Java多线程中ReentrantLock与Condition详解,需要的朋友可以参考下
    2017-11-11
  • springboot 加载 META-INF/spring.factories方式

    springboot 加载 META-INF/spring.factories方式

    这篇文章主要介绍了springboot 加载 META-INF/spring.factories方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • SpringBoot自定义注解使用读写分离Mysql数据库的实例教程

    SpringBoot自定义注解使用读写分离Mysql数据库的实例教程

    这篇文章主要给大家介绍了关于SpringBoot自定义注解使用读写分离Mysql数据库的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • java如何遍历对象中的所有属性(字段)和类型

    java如何遍历对象中的所有属性(字段)和类型

    这篇文章主要介绍了java如何遍历对象中的所有属性(字段)和类型问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • Java中SimpleDateFormat的使用方法

    Java中SimpleDateFormat的使用方法

    这篇文章主要为大家详细介绍了Java中SimpleDateFormat的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12
  • Java利用反射自动封装成实体对象的方法

    Java利用反射自动封装成实体对象的方法

    这篇文章主要介绍了Java利用反射自动封装成实体对象的方法,可实现自动封装成bean对象功能,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-01-01
  • SpringBoot结合ProGuard实现代码混淆(最新版)

    SpringBoot结合ProGuard实现代码混淆(最新版)

    这篇文章主要介绍了SpringBoot结合ProGuard实现代码混淆(最新版),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10

最新评论