zoukankan      html  css  js  c++  java
  • ReadWriteLock锁的应用

    对于 Lock 锁来说,如果要实现 “一写多读” 的并发状态(即允许同时读,不允许同时写),需要对 “写操作” 加锁,对 “读操作” 不作要求即可。但是如果对于 “读” 操作下,有 “写操作” 接入的话,对于当前的 “读操作” 可能会产生 “幻读” 的现象。所以对于要实现 “一写多读” 的情况下,应推荐使用 ReadWriteLock 锁。

    ReadWriteLock 是与 Lock 平级的一个 JUC 包下的接口

    它唯一的实现类是 ReentrantReadWriteLock 类,一个 ReentrantReadWriteLock 对象维护了一对关联的locks ,一个用于只读操作,一个用于写入。

    简单来说:

    • 它维护了两个锁,一个叫 “读锁”,一个叫 “写锁”。
    • 为了允许 “一写多读” 的操作,按理上,“写锁” 一旦上锁,不能再被获取;而为了保证能同时读数据,“读锁” 若上锁,想获取 “读锁” 的线程仍然可以执行读操作,而为了防止 “读操作” 执行时有 “写操作” 的接入,应该要防止 “写锁” 被获取。

    下面通过 4 个不同顺序的读写实例来演示一遍(代码贴在最后面)

    1、一个线程已获取 “写锁” 状态下,另一个线程尝试获取 “读锁” 。





    在 “读锁” 已被获取的情况下,“写锁” 不能被获取。(即便是在多个线程都获取 “读锁”,“写锁” 必须在所有 “读操作” 结束后才能被获取,可自行测试)

    2、一个线程已获取 “读锁” 状态下,另一个线程尝试获取 “写锁” 。





    在 “写锁” 已被获取的情况下,“读锁” 不能被获取。

    3、一个线程已获取 “读锁” 状态下,另一个线程尝试获取 “读锁” 。





    在 “读锁” 已被获取的情况下,“读锁” 还能再被获取,类似于 Semaphore 辅助类。

    4、一个线程已获取 “写锁” 状态下,另一个线程尝试获取 “写锁” 。





    在 “写锁” 已被获取的情况下,“写锁” 不能再被获取。


    总代码

    package ReadWriteLock;
    
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class ReadWriteLockDemo {
    
        private final static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    
        public static void main(String[] args) throws InterruptedException {
            writeAndWriteTest();
        }
    
        public static void readAndWriteTest() throws InterruptedException {
            //第一个线程先获取写锁,另一个线程再获取读锁
            new Thread(() -> {
                readWriteLock.writeLock().lock();
                System.out.println("写锁已获取");
                try {
                    Thread.sleep(8000);
                    readWriteLock.writeLock().unlock();
                    System.out.println("已关闭写锁");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
            Thread.sleep(3000);
            System.out.println("另一个线程尝试获取读锁");
            new Thread(() -> {
                readWriteLock.readLock().lock();
                System.out.println("另一个线程的读锁已获取");
            }).start();
        }
    
        public static void writeAndReadTest() throws InterruptedException {
            //第一个线程先获取读锁,另一个线程再获取写锁
            new Thread(() -> {
                readWriteLock.readLock().lock();
                System.out.println("读锁已获取");
                try {
                    Thread.sleep(8000);
                    readWriteLock.readLock().unlock();
                    System.out.println("已关闭读锁");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
            Thread.sleep(3000);
            System.out.println("另一个线程尝试获取写锁");
            new Thread(() -> {
                readWriteLock.writeLock().lock();
                System.out.println("另一个线程的写锁已获取");
            }).start();
        }
    
        public static void readAndReadTest() throws InterruptedException {
            //一个线程已获读锁,另一个线程再获取读锁
            new Thread(() -> {
                readWriteLock.readLock().lock();
                System.out.println("读锁已获取");
                try {
                    Thread.sleep(8000);
                    readWriteLock.readLock().unlock();
                    System.out.println("已关闭读锁");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
            Thread.sleep(3000);
            System.out.println("另一个线程尝试获取读锁");
            new Thread(() -> {
                readWriteLock.readLock().lock();
                System.out.println("另一个线程的读锁已获取");
            }).start();
        }
    
        public static void writeAndWriteTest() throws InterruptedException {
            //一个线程已获写锁,另一个线程再获取写锁
            new Thread(() -> {
                readWriteLock.writeLock().lock();
                System.out.println("写锁已获取");
                try {
                    Thread.sleep(8000);
                    readWriteLock.writeLock().unlock();
                    System.out.println("已关闭写锁");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
            Thread.sleep(3000);
            System.out.println("另一个线程尝试获取写锁");
            new Thread(() -> {
                readWriteLock.writeLock().lock();
                System.out.println("另一个线程的写锁已获取");
            }).start();
        }
    }
    

    总结

    ReentrantReadWriteLock 中的 “写锁” 类似于 Lock 锁,而 “读锁” 类似于 Semaphore 信号量机制。“写锁” 保证临界资源能被唯一占用,解决了 “写写同步问题”。而当且仅当 “读锁” 队列为空时,“写锁” 才能被获取。且 “写锁” 和 “读锁” 在同一时刻不能同时被持有,解决了 “读写同步问题”,且它还能保证能够 “同时读” 的特性。

  • 相关阅读:
    我的大学生涯
    如何设计一个好的Windows 8应用
    [置顶] 十大高明的Google搜索技巧
    [置顶] 走出困境靠自己
    Android代码混淆前后分析
    百度高级搜索
    未来手机什么样 十款未来概念手机图赏
    如何看懂Java混淆后的反编译代码
    最值得一看的几条简单的谷歌 Google 搜索技巧,瞬间提升你的网络搜索能力!
    各种网页尺寸判断方法
  • 原文地址:https://www.cnblogs.com/Absofuckinglutely/p/13280042.html
Copyright © 2011-2022 走看看