面试官:谈谈读写锁--ReadWriteLock

简介: 面试官:谈谈读写锁--ReadWriteLock

今天来说说Java 的读写锁-ReadWriteLock,ReadWriteLock是一个接口,实现类是ReentrantReadWriteLock,看着名字的翻译就是可重入读写锁。


为什么Java会搞了那么多种类的锁,因为不同的场景需要做不同的适配来达到性能和使用的最优,而读写锁的使用场景就是读多写少。


读写锁是什么?


读写锁就是分了两种情况,一种是读时的锁,一种是写时的锁,它允许多个线程同时读共享变量,但是只允许一个线程写共享变量,当写共享变量的时候也会阻塞读的操作。这样在读的时候就不会互斥,提高读的效率。


可重入锁是什么?


可重入锁指的是在同一个线程内如果你的外层函数已经获得了锁,那么当你的内层函数也能获取锁,也就是通过一个线程再次进入同步代码块时可以获得自己已经获得的锁,而不可重入则反之。看下简单的示例


public void doSth(){   //外层函数
        lock.lock();
        do();  //内层函数
        lock.unlock();
    }
    public void do(){
        lock.lock();
        //do something
        lock.unlock();
     }


可重入锁这样使用上面代码是没问题的,如果不可重入锁这样的调用是不允许的。

来看看Javadoc中ReentrantReadWriteLock的示例,主要说的就是处理一个获取一个缓存数据的示例


class CachedData {
   Object data;
   volatile boolean cacheValid;
   final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
   void processCachedData() {
     rwl.readLock().lock();   //先获取读锁
     if (!cacheValid) {  //如果缓存失效,那表示需要重新去获取数据写入缓存,所以就得变成写锁
        // Must release read lock before acquiring write lock (在获取写锁前必须释放读锁)
        rwl.readLock().unlock();
        rwl.writeLock().lock();
        try {
          // Recheck state because another thread might have
          // acquired write lock and changed state before we did.
          // (重新检查状态,因为有可能别的线程已经在当前线程获取写锁时已经更新了缓存)
          if (!cacheValid) {
            data = ...
            cacheValid = true;
          }
          // Downgrade by acquiring read lock before releasing write lock
          // (通过在释放写锁之前获取读锁来降级)
          rwl.readLock().lock();
        } finally {                 //(释放写锁,仍持有写锁)
          rwl.writeLock().unlock(); // Unlock write, still hold read
        }
     }
     try {
       use(data);
     } finally {
       rwl.readLock().unlock();
     }
   }
 }


可以看出使用还是简单的,相对于ReentrantLock来说就是多了个角色区别一个是读锁一个是写锁。


读写锁的升降级



上面代码有提到


Must release read lock before acquiring write lock (在获取写锁前必须释放读锁)

也就是说 读写锁不允许锁的升级,不能直接从读锁升级到写锁。 如果读锁还没有释放,此时获取写锁,会导致写锁永久等待,最终导致相关线程都阻塞,GG。切记不可这样使用


但是锁的降级是允许的


Downgrade by acquiring read lock before releasing write lock(通过在释放写锁之前获取读锁来降级)


也就是说在释放写锁之前可以获取读锁来达到锁的降级!


读写锁还有一点不同就是写锁是支持条件变量的也就是支持newCondition,而读锁是不支持条件变量的,如果读锁调用newCondition会抛UnsupportedOperationException


读写锁实现了java.util.concurrent.locks.Lock接口,所以tryLock()、lockInterruptibly()等方法都是支持的,并且也支持公平锁和非公平锁的模式,底层是也是基于AbstractQueuedSynchronizer实现的,所以对于公平和非公平锁的实现可以参见面试官:说说Java中的信号量?Semaphore 我的这篇文章



相关文章
|
1月前
|
存储 关系型数据库 MySQL
最全MySQL面试60题(含答案):存储引擎+数据库锁+索引+SQL优化等
最全MySQL面试60题(含答案):存储引擎+数据库锁+索引+SQL优化等
162 0
|
7月前
|
Java
「Java面试」被这题怼到不行,什么是可重入锁能解决什么问题?
一位3年工作经验的小伙伴,去一家互联网公司面试,结果被面试官怼了。面试官说:”这么简单的问题你都不知道?没法聊了,回去等通知吧“。然后,回来跟我是一阵诉苦。
72 0
|
11天前
|
安全 Java
大厂面试题详解:synchronized的偏向锁和自旋锁怎么实现的
字节跳动大厂面试题详解:synchronized的偏向锁和自旋锁怎么实现的
9 0
|
2月前
|
机器学习/深度学习 算法 搜索推荐
|
7月前
|
缓存 安全 Java
解锁Java面试中的锁:深入了解不同类型的锁和它们的用途
多线程编程在现代软件开发中扮演着至关重要的角色。它使我们能够有效地利用多核处理器和提高应用程序的性能。然而,多线程编程也伴随着一系列挑战,其中最重要的之一就是处理共享资源的线程安全性。在这个领域,锁(Lock)是一个关键的概念,用于协调线程之间对共享资源的访问。本文将深入探讨Java中不同类型的锁以及它们的应用。我们将从基本概念开始,逐步深入,帮助您了解不同类型的锁以及如何选择合适的锁来解决多线程编程中的问题。
|
3月前
|
算法 Java
【面试问题】锁如何优化?
【1月更文挑战第27天】【面试问题】锁如何优化?
|
3月前
|
监控 Java
【面试问题】什么是锁的自适应自旋?
【1月更文挑战第27天】【面试问题】什么是锁的自适应自旋?
|
3月前
|
设计模式 消息中间件 Java
面试官:什么是JIT、逃逸分析、锁消除、栈上分配和标量替换?
面试官:什么是JIT、逃逸分析、锁消除、栈上分配和标量替换?
523 1
|
8月前
|
存储 Java
第二季:5公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解?请手写一个自旋锁【Java面试题】
第二季:5公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解?请手写一个自旋锁【Java面试题】
32 0
|
8月前
|
Java
【java常见的面试题】加锁的方式有哪些 ?
Java基础的面试题加锁的方式有哪些 ?