首页 > 图灵资讯 > java面试题>正文
如何在Java中实现可重入读写锁(ReentrantReadWriteLock)?
2025-02-17 14:21:55
在Java中,如果我们想让多个线程可以同时读取数据,但写数据的时候又要确保只有一个线程能操作,并且写的时候不能有线程在读,那就可以用一种叫“读写锁”的机制。而“可重入读写锁”(ReentrantReadWriteLock)正是Java里提供的一个现成的工具类,专门用来解决这种问题。
什么是可重入读写锁?
-
读锁和写锁分开:
- 读锁:允许多个线程同时读取数据,但不能写。
- 写锁:只有一个线程能写,同时禁止其他线程读或写。
-
可重入:意思是,如果一个线程已经拿到了锁,它可以再次进入锁的代码块,而不会被锁挡住。比如,一个线程已经获取了写锁,接下来如果它又想获取写锁,就不会再卡住。
为什么要用可重入读写锁?
举个例子:想象一下,你和朋友们去图书馆借书。
- 如果你们只是“看书”(读操作),大家可以一起看,不会互相打扰。
- 但如果你需要“修改书本内容”(写操作),为了不影响别人看书,图书馆会让所有人先停下来,等你修改完后再继续看。
在程序里也是类似的:
- 读操作是“多线程共享”,效率更高。
- 写操作是“单线程独占”,保证数据的安全性。
如何在Java中实现?
Java提供了ReentrantReadWriteLock
这个工具类,它分为两部分:
- 读锁(read lock):用来控制读操作。
- 写锁(write lock):用来控制写操作。
使用它的步骤:
- 首先,创建一个
ReentrantReadWriteLock
对象。 - 通过这个对象,可以分别获取“读锁”和“写锁”。
- 在需要读或者写的地方,先获取对应的锁。
- 用完后,记得释放锁。
锁的具体行为:
- 如果一个线程获取了读锁,其他线程也可以获取读锁,但不能获取写锁。
- 如果一个线程获取了写锁,其他线程既不能获取读锁,也不能获取写锁。
- 如果有线程正在等着获取写锁,新的读锁请求会被阻塞,优先让写锁完成。
注意事项
- 避免死锁:一定要按顺序释放锁。如果一个线程同时持有读锁和写锁,释放时需要确保写锁先释放,然后再释放读锁。
- 性能选择:读写锁适合“读多写少”的场景。如果写操作很频繁,可能会降低性能。
- 公平性:
ReentrantReadWriteLock
默认是非公平的,也就是说,线程获取锁的顺序不一定按先来先得。如果需要公平性,可以通过构造方法设置。
总结
ReentrantReadWriteLock
就像图书馆管理员一样,负责管理“读者”和“修改者”的进出:
- 读者可以一起进来,但修改者需要单独操作。
- 如果有人正在修改,读者和其他修改者都得等。
- 如果用的人多了,还可以调整规则,让大家按顺序来。
