[Java高并发编程](四)Lock的使用之ReentrantReadWriteLock读写锁

本博客根据《Java并发编程的艺术》学习整理而来

  在之前我们提到的ReentrantLock可重入锁等锁基本上都是排他锁,这些锁在同一时刻只允许一个线程进行访问,而读写锁在同一时刻可以允许多个读线程访问,但是在写线程访问时,所有的读线程和其他写线程均被阻塞。读写锁维护了一对锁,一个读锁和一个写锁,通过分离读锁和写锁,使得并发性相比一般的排他锁有了很大的提升。
  ReadWriteLock是JDK5中提供的读写分离锁。读写分离锁可以有效地帮助减少竞争,以提升系统性能,读写锁的访问约束情况如下:

读读共享、写写互斥、读写互斥

由此可见,如果在系统中,读操作次数远远大于写操作,则读写锁就可以发挥最大的功效,提升系统的性能。
让我们用下面的例子来直观的感受一下:

public class Test10 {
    private static Lock lock = new ReentrantLock();  //定义可重入锁
    private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private static Lock readLock = readWriteLock.readLock(); //定义读锁
    private static Lock writeLock = readWriteLock.writeLock();//定义写锁
    private int value;

    //模拟读操作的方法
    public Object handleRead(Lock lock) throws InterruptedException {
        lock.lock();   
        try {
            Thread.sleep(5000);  //读操作耗时越多,读写锁的优势越明显
            return value;
        } finally {
            lock.unlock();
        }
    }

    //模拟写操作的方法
    public void handleWrite(Lock lock, int index) throws InterruptedException {
        lock.lock(); 
        try {
            Thread.sleep(1000);
            value = index;
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {

        ExecutorService executorService = Executors.newFixedThreadPool(5); //定义一个线程池
        long start = System.currentTimeMillis();
        Test10 test = new Test10();
        for (int i = 0; i < 2; i++) {
            executorService.execute(() -> {
                try {
                    test.handleRead(lock); //普通锁
                  //test.handleRead(readLock); //读锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });

            executorService.execute(() -> {
                try {
                    test.handleWrite(lock, new Random().nextInt());  //普通锁
                  //test.handleWrite(writeLock,new Random().nextInt());  //写锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        executorService.shutdown();

        while (true) {
            if (executorService.isTerminated()) {
                long end = System.currentTimeMillis();
              //System.out.println("使用读写锁用时: " + (end - start) + "ms");
                System.out.println("使用普通锁锁用时: " + (end - start) + "ms");
                break;
            }
        }
    }
}

运行结果:

  • 当执行普通锁的时候
    [Java高并发编程](四)Lock的使用之ReentrantReadWriteLock读写锁_第1张图片
  • 当执行读写锁的时候
    [Java高并发编程](四)Lock的使用之ReentrantReadWriteLock读写锁_第2张图片

有上面的可以看出,读写锁的效率还是非常高的。

读写锁的实践应用例子

public class CacheDemo {

    static Map map = new HashMap<>();
    static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    static Lock r = rwl.readLock();
    static Lock w = rwl.writeLock();
    // 获取一个key对应的value
    public static final Object get(String key)  {
        r.lock();
        try {
            return map.get(key);
        } finally {
            r.unlock();
        }
    }
    // 设置key对应的value,并返回旧的value
    public static final Object put(String key, Object value){
        w.lock();
        try {
            return map.put(key, value);
        } finally {
            w.unlock();
        }
    }
}

你可能感兴趣的:([Java高并发编程](四)Lock的使用之ReentrantReadWriteLock读写锁)