面试突击45:为什么要用读写锁?它有什么优点?
2023-04-18 14:39:12 时间
读写锁(Readers-Writer Lock)顾名思义是一把锁分为两部分:读锁和写锁,其中读锁允许多个线程同时获得,因为读操作本身是线程安全的,而写锁则是互斥锁,不允许多个线程同时获得写锁,并且写操作和读操作也是互斥的。总结来说,读写锁的特点是:读读不互斥、读写互斥、写写互斥。
1.读写锁使用
在 Java 语言中,读写锁是使用 ReentrantReadWriteLock 类来实现的,其中:
- ReentrantReadWriteLock.ReadLock 表示读锁,它提供了 lock 方法进行加锁、unlock 方法进行解锁。
- ReentrantReadWriteLock.WriteLock 表示写锁,它提供了 lock 方法进行加锁、unlock 方法进行解锁。
它的基础使用如下代码所示:
// 创建读写锁
final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 获得读锁
final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
// 获得写锁
final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
// 读锁使用
readLock.lock();
try {
// 业务代码...
} finally {
readLock.unlock();
}
// 写锁使用
writeLock.lock();
try {
// 业务代码...
} finally {
writeLock.unlock();
}
1.1 读读不互斥
多个线程可以同时获取到读锁,称之为读读不互斥,如下代码所示:
// 创建读写锁
final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 创建读锁
final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
Thread t1 = new Thread(() -> {
readLock.lock();
try {
System.out.println("[t1]得到读锁.");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[t1]释放读锁.");
readLock.unlock();
}
});
t1.start();
Thread t2 = new Thread(() -> {
readLock.lock();
try {
System.out.println("[t2]得到读锁.");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[t2]释放读锁.");
readLock.unlock();
}
});
t2.start();
以上程序执行结果如下:
1.2 读写互斥
读锁和写锁同时使用是互斥的(也就是不能同时获得),这称之为读写互斥,如下代码所示:
// 创建读写锁
final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 创建读锁
final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
// 创建写锁
final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
// 使用读锁
Thread t1 = new Thread(() -> {
readLock.lock();
try {
System.out.println("[t1]得到读锁.");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[t1]释放读锁.");
readLock.unlock();
}
});
t1.start();
// 使用写锁
Thread t2 = new Thread(() -> {
writeLock.lock();
try {
System.out.println("[t2]得到写锁.");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[t2]释放写锁.");
writeLock.unlock();
}
});
t2.start();
以上程序执行结果如下:
1.3 写写互斥
多个线程同时使用写锁也是互斥的,这称之为写写互斥,如下代码所示:
// 创建读写锁
final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 创建写锁
final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
Thread t1 = new Thread(() -> {
writeLock.lock();
try {
System.out.println("[t1]得到写锁.");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[t1]释放写锁.");
writeLock.unlock();
}
});
t1.start();
Thread t2 = new Thread(() -> {
writeLock.lock();
try {
System.out.println("[t2]得到写锁.");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("[t2]释放写锁.");
writeLock.unlock();
}
});
t2.start();
以上程序执行结果如下:
2.优点分析
-
提高了程序执行性能:多个读锁可以同时执行,相比于普通锁在任何情况下都要排队执行来说,读写锁提高了程序的执行性能。
-
避免读到临时数据:读锁和写锁是互斥排队执行的,这样可以保证了读取操作不会读到写了一半的临时数据。
3.适用场景
读写锁适合多读少写的业务场景,此时读写锁的优势最大。
总结
读写锁是一把锁分为两部分:读锁和写锁,其中读锁允许多个线程同时获得,而写锁则是互斥锁。它的完整规则是:读读不互斥、读写互斥、写写互斥。它适用于多读的业务场景,使用它可以有效的提高程序的执行性能,也能避免读取到操作了一半的临时数据。
是非审之于己,毁誉听之于人,得失安之于数。
公众号:Java面试真题解析
相关文章
- 把Transformer当通用计算机用,还能执行in-context learning算法,这项研究脑洞大开
- 看 Serverless Task 如何解决任务调度&可观测性中的问题
- 狂揽两千星,速度百倍提升,高性能Python编译器Codon开源
- ChatGPT发明「史莱姆语」,词汇语法规则全都有,还配了「史翻英」Python代码
- 功能安全机制:内存分区与实现
- 揭秘字节跳动解决ClickHouse复杂查询问题的技术实践
- 研发效能提升利器:五个AI编程助手
- 都2022年了,Python继续霸榜,SQL写得溜,面试或能加分
- 编程语言大对决!Ruby和Python谁更可读?
- 《基于Python鸿蒙开发板外设控制》直播图文及答疑
- 手把手教你安装MINIGUI编程环境 (MINIGUI版本3.2.0)
- Chrome 94 新 API 引争议,Mozilla 和苹果联合反对
- 如何在Ubuntu 20.04上创建Python虚拟环境?
- Ubuntu 20.04 设置 Python 项目环境的正确姿势
- 用 Python 帮小伙伴找到头上一片绿的证据!
- 为什么在 Windows 下用 Ctrl+Z 退出 Python 而 Linux 下用 Ctrl+D 呢?
- 进入内核态究竟是什么意思?
- 事实证明:要想获得Windows 10 管理员权限,只需插入“雷蛇鼠标”即可
- Windows 10电脑怎么合并不相邻磁盘?
- 聊聊 top 命令中的 CPU 使用率