吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1034|回复: 1
收起左侧

[学习记录] Java中读写锁ReadWriteLock的使用案例和性能对比

  [复制链接]
黑白客 发表于 2022-11-16 18:12
本帖最后由 黑白客 于 2022-11-16 18:22 编辑

ReadWriteLock介绍

ReadWriteLock 被称为读写锁,通过读读不加锁的方式区分业务,从而提高效率

读写锁与ReentLock锁的效率对比
我们用如下代码进行一个简单的对比

非公平模式(默认)
当以非公平初始化时,读锁和写锁的获取的顺序是不确定的。非公平锁主张竞争获取,可能会延缓一个或多个读或写线程,但是会比公平锁有更高的吞吐量。
公平模式
当以公平模式初始化时,线程将会以队列的顺序获取锁。当当前线程释放锁后,等待时间最长的写锁线程就会被分配写锁;或者有一组读线程组等待时间比写线程长,那么这组读线程组将会被分配读锁。

实例代码和性能对比

建议看着demo自己敲一下,可能会发现很多新的问题,记忆也更牢固

package ReentrantLock和LongAdder;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @program: solution
 * @description: 演示ReadWriteLock的使用
 * @author: Wang Hai Xin
 * @create: 2022-11-14 10:10
 **/
public class ReadWritLockT {

    /**/
    static ReentrantLock lock = new ReentrantLock();

    static int value = 0;

    /*读写锁,ReentrantReadWriteLock 是读写锁ReadWriteLock的一种实现*/
    static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    /*可以通过 redLocke和writeLock分出两把锁使用*/
    static Lock read = readWriteLock.readLock();
    static Lock write = readWriteLock.writeLock();

    public static void main(String[] args) {

        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        String format = simpleDateFormat.format(date);

        Runnable writeRunnable = () -> write(lock, 1);

//        Runnable writeRunnable = () -> write(write, 1);

        Runnable readRunnable = () -> read(lock);
//
//        Runnable readRunnable = () -> read(read);

        ArrayList<Thread> threads = new ArrayList<>();
        for (int i = 0; i < 18; i++) {
            threads.add(
                    new Thread(readRunnable)
            );

        }

        for (int i = 0; i < 2; i++) {
            threads.add(
                    new Thread(writeRunnable)
            );
        }

        for (int i = 0; i < threads.size(); i++) {
            threads.get(i).start();
        }

        for (int i = 0; i < threads.size(); i++) {
            try {
                threads.get(i).join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        System.out.println("ReentrantLock开始时间"+format);

        Date date1 = new Date();
        SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        String format1 = simpleDateFormat1.format(date1);
        System.out.println("ReentLock 结束时间:" + format1);

    }

    public static void read(Lock lock) {

        try {
            lock.lock();
            Thread.sleep(1000);
            System.out.println("读数据结束");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }

    }

    public static void write(Lock lock, int i) {
        try {
            lock.lock();
            Thread.sleep(1000);
            value += i;
            System.out.println("写操作完成");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }

}

ReentrantLock运行结果

读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
写操作完成
写操作完成
ReentrantLock开始时间2022-11-14 10:46:20 217
ReentLock 结束时间:2022-11-14 10:46:40 476

使用ReentrantReadWriteLock运行的结果为

//        Runnable writeRunnable = () -> write(lock, 1);
//
Runnable writeRunnable = () -> write(write, 1);
//
//        Runnable readRunnable = () -> read(lock);
Runnable readRunnable = () -> read(read);

读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
读数据结束
写操作完成
写操作完成
ReentrantLock开始时间2022-11-14 10:48:45 604
ReentLock 结束时间:2022-11-14 10:48:48 701

可以看出 在特定条件下,ReentrantReadWritLock的效率要比Reentrantlock的效率高很多。

使用场景以及注意事项

使用场景应该很好想了,就是读多写少的场景可以使用.

笔者不太推荐使用,
因为维护起来会很麻烦,如果业务逻辑复杂,后来的人很有可能就在读的逻辑中操作了数据。

锁降级

要实现一个读写锁,需要考虑很多细节,其中之一就是锁升级和锁降级的问题。什么是升级和降级呢?

在不允许中间写入的情况下,写入锁可以降级为读锁吗?读锁是否可以升级为写锁,优先于其他等待的读取或写入操作?简言之就是说,锁降级:从写锁变成读锁;锁升级:从读锁变成写锁,ReadWriteLock是否支持呢?

ReadWriteLock 不支持锁升级

ReadWriteLock 支持锁降级,但是!! 并不会自动释放写锁,需要显式的释放写锁,否则其它线程永远获取不到写锁

免费评分

参与人数 2吾爱币 +2 热心值 +2 收起 理由
zimu217 + 1 + 1 我很赞同!
gdhgn + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Nemoris丶 发表于 2022-11-16 21:28
学习了!!!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-1-12 01:43

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表