ReentrantReadWriteLock读写锁(读多写少场景)

ReentrantReadWriteLock读写锁

适合读多写少的场景。

读锁ReentrantReadWriteLock.ReadLock可以被多个线程同时持有, 所以并发能力很高。

写锁ReentrantReadWriteLock.WriteLock是独占锁, 在一个线程持有写锁时候, 其他线程都不能在抢占, 包含抢占读锁都会阻塞。

读写锁的互斥原则如下:

  • 读操作与读操作, 线程之间是可以共存的, 是相容的。
  • 读操作与写操作、 线程之间不能共存的, 是互斥的、 当有写锁操作时候, 其他线程抢占读写锁都会等待阻塞。
  • 写操作与写操作、线程之间不能共存的, 是互斥的、 当有写锁操作时候, 其他线程抢占读写锁都会等待阻塞。

例子:

// 可重入读写锁 (默认非公平)
    private final static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    // 读写锁
    private final static ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
    private final static ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
    // 共享临界资源
    private volatile static Map<String, String> map = new HashMap<>();

    @Test
    public void applicationTest() throws Throwable {
        map.put("1", "1-1");
        // 并发20个线程同时去读
        for (int i = 0; i < 20; i++) {
            int j = i;
            int finalJ = j;
            executor.execute(() -> {
                Thread thread = Thread.currentThread();
                String threadName = thread.getName();
                try {
                    // 大家都停止一会, 进行并发抢占锁
                    TimeUnit.SECONDS.sleep(3);

                    if (finalJ > 15) {
                        log.info(threadName + "线程暂停5秒啦");
                        // 15个线程后暂停5秒后在继续抢占读锁
                        TimeUnit.SECONDS.sleep(5);
                    }
                    readLock.lock();
                    log.info(threadName + "线程加读锁成功、读取到值" + map.toString());
                } catch (InterruptedException e) {
                    log.error(threadName + "加锁失败啦");
                } finally {
                    Tools.catchNoLogs(readLock::unlock);
                }
            });
        }
        // 8秒后进行写操作
        TimeUnit.SECONDS.sleep(8);
        writeLock.lock();
        try {
            map.put("name", "进行写入啦!");
            log.info("主线程加写锁写入啦, 并写完, 不释放写锁8秒");
            TimeUnit.SECONDS.sleep(8);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            log.info("主线程写锁释放啦、 下面读锁可以继续抢占到读锁进行读取");
            Tools.catchNoLogs(writeLock::unlock);
        }
        TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
    }

结果:

从结果可以看出, 读锁可以多个线程同时抢占!

20:33:42.533 [[my-thread-2]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-2]线程加读锁成功、读取到值{1=1-1}
20:33:42.533 [[my-thread-15]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-15]线程加读锁成功、读取到值{1=1-1}
20:33:42.534 [[my-thread-6]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-6]线程加读锁成功、读取到值{1=1-1}
20:33:42.534 [[my-thread-3]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-3]线程加读锁成功、读取到值{1=1-1}
20:33:42.534 [[my-thread-1]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-1]线程加读锁成功、读取到值{1=1-1}
20:33:42.533 [[my-thread-11]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-11]线程加读锁成功、读取到值{1=1-1}
20:33:42.534 [[my-thread-9]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-9]线程加读锁成功、读取到值{1=1-1}
20:33:42.534 [[my-thread-13]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-13]线程加读锁成功、读取到值{1=1-1}
20:33:42.533 [[my-thread-7]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-7]线程加读锁成功、读取到值{1=1-1}
20:33:42.534 [[my-thread-10]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-10]线程加读锁成功、读取到值{1=1-1}
20:33:42.534 [[my-thread-8]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-8]线程加读锁成功、读取到值{1=1-1}
20:33:42.534 [[my-thread-4]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-4]线程加读锁成功、读取到值{1=1-1}
20:33:42.535 [[my-thread-12]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-12]线程加读锁成功、读取到值{1=1-1}
20:33:42.535 [[my-thread-5]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-5]线程加读锁成功、读取到值{1=1-1}
20:33:42.535 [[my-thread-16]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-16]线程加读锁成功、读取到值{1=1-1}
20:33:42.535 [[my-thread-14]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-14]线程加读锁成功、读取到值{1=1-1}
20:33:45.543 [[my-thread-12]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-12]线程暂停5秒啦
20:33:45.544 [[my-thread-8]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-8]线程暂停5秒啦
20:33:45.544 [[my-thread-6]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-6]线程暂停5秒啦
20:33:45.544 [[my-thread-4]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-4]线程暂停5秒啦
20:33:47.508 [main] INFO com.zhihao.demo.DemoApplicationTests - 主线程加写锁写入啦, 并写完, 不释放写锁8秒
20:33:55.508 [main] INFO com.zhihao.demo.DemoApplicationTests - 主线程写锁释放啦、 下面读锁可以继续抢占到读锁进行读取
20:33:55.510 [[my-thread-6]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-6]线程加读锁成功、读取到值{1=1-1, name=进行写入啦!}
20:33:55.510 [[my-thread-12]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-12]线程加读锁成功、读取到值{1=1-1, name=进行写入啦!}
20:33:55.510 [[my-thread-8]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-8]线程加读锁成功、读取到值{1=1-1, name=进行写入啦!}
20:33:55.510 [[my-thread-4]] INFO com.zhihao.demo.DemoApplicationTests - [my-thread-4]线程加读锁成功、读取到值{1=1-1, name=进行写入啦!}

1

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

懵懵懂懂程序员

如果节省了你的时间, 请鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值