java key锁_Java锁_读写锁

本文通过实例代码展示了Java中ReentrantReadWriteLock如何解决并发问题,对比了Synchronized和ReentrantLock,解释了读写锁的概念,强调了读-读能共存、读-写及写-写不能共存的原则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

独占锁:是指锁一次只能被一个线程持有,ReentrantLock和Synchronized都是独占锁。

共享锁:是指锁可以被多个线程持有。

对于ReentrantReadWriteLock,其读锁是共享锁,写锁是独占锁。

代码示例:如果不设置锁,下面这块代码执行后就会造成一段写操作在完成之前被多个其他操作打断。

1 packagecom.freud.algorithm.other;2

3 importjava.util.HashMap;4 importjava.util.Map;5 importjava.util.concurrent.TimeUnit;6 importjava.util.concurrent.locks.Lock;7 importjava.util.concurrent.locks.ReentrantLock;8

9 /**

10 * 资源类11 */

12 classMyCache {13

14 private volatile Map map = new HashMap<>();15 //private Lock lock = new ReentrantLock();

16 public voidput(String key, Object value) {17

18 System.out.println(Thread.currentThread().getName() + "t 正在写入:" +key);19 //暂停一会儿线程

20 try{21 TimeUnit.MILLISECONDS.sleep(300);22 } catch(InterruptedException e) {23 e.printStackTrace();24 }25 map.put(key, value);26 System.out.println(Thread.currentThread().getName() + "t 写入完成");27 }28

29 public voidget(String key) {30

31 System.out.println(Thread.currentThread().getName() + "t 正在读取:");32 //暂停一会儿线程

33 try{34 TimeUnit.MILLISECONDS.sleep(300);35 } catch(InterruptedException e) {36 e.printStackTrace();37 }38 Object value =map.get(key);39 System.out.println(Thread.currentThread().getName() + "t 读取完成:" +value);40 }41 }42

43 /**

44 * 多个线程同时读一个资源类没有任何问题,所以为了满足并发量,读取共享资源应该可以同时进行45 * 但是,如果有一个线程想去写共享资源,就不应该再有其他线程可以对这个资源进行读或者写46 * 小总结:47 * 读-读能共存48 * 读-写不能共存49 * 写-写不能共存50 */

51 public classReadWriteLockDemo {52

53 public static voidmain(String[] args) {54

55 MyCache myCache = newMyCache();56

57 for (int i = 0; i < 5; i++) {58 final int tempInt =i;59 new Thread(() ->{60 myCache.put(tempInt + "", tempInt + "");61 }, String.valueOf(i)).start();62 }63

64 for (int i = 0; i < 5; i++) {65 final int tempInt =i;66 new Thread(() ->{67 myCache.get(tempInt + "");68 }, String.valueOf(i)).start();69 }70 }71 }

打印:

1 "C:Program FilesJavajdk1.8.0_191binjava" "-javaagent:E:JetbrainsIntellijIDEAIntelliJ IDEA 2017.2.6libidea_rt.jar=12592:E:JetbrainsIntellijIDEAIntelliJ IDEA 2017.2.6bin" -Dfile.encoding=UTF-8 -classpath "C:Program FilesJavajdk1.8.0_191jrelibcharsets.jar;C:Program FilesJavajdk1.8.0_191jrelibdeploy.jar;C:Program FilesJavajdk1.8.0_191jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.8.0_191jrelibextcldrdata.jar;C:Program FilesJavajdk1.8.0_191jrelibextdnsns.jar;C:Program FilesJavajdk1.8.0_191jrelibextjaccess.jar;C:Program FilesJavajdk1.8.0_191jrelibextjfxrt.jar;C:Program FilesJavajdk1.8.0_191jrelibextlocaledata.jar;C:Program FilesJavajdk1.8.0_191jrelibextnashorn.jar;C:Program FilesJavajdk1.8.0_191jrelibextsunec.jar;C:Program FilesJavajdk1.8.0_191jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.8.0_191jrelibextsunmscapi.jar;C:Program FilesJavajdk1.8.0_191jrelibextsunpkcs11.jar;C:Program FilesJavajdk1.8.0_191jrelibextzipfs.jar;C:Program FilesJavajdk1.8.0_191jrelibjavaws.jar;C:Program FilesJavajdk1.8.0_191jrelibjce.jar;C:Program FilesJavajdk1.8.0_191jrelibjfr.jar;C:Program FilesJavajdk1.8.0_191jrelibjfxswt.jar;C:Program FilesJavajdk1.8.0_191jrelibjsse.jar;C:Program FilesJavajdk1.8.0_191jrelibmanagement-agent.jar;C:Program FilesJavajdk1.8.0_191jrelibplugin.jar;C:Program FilesJavajdk1.8.0_191jrelibresources.jar;C:Program FilesJavajdk1.8.0_191jrelibrt.jar;E:practisealgorithmoutproductionalgorithm"com.freud.algorithm.other.ReadWriteLockDemo2 1 正在写入:1

3 0 正在写入:0

4 2 正在写入:2

5 3 正在写入:3

6 4 正在写入:4

7 0正在读取:8 1正在读取:9 2正在读取:10 3正在读取:11 4正在读取:12 1写入完成13 1 读取完成:1

14 0 读取完成:0

15 0写入完成16 2写入完成17 4写入完成18 3写入完成19 4 读取完成:null

20 3 读取完成:null

21 2 读取完成:2

22

23 Process finished with exit code 0

为了解决这个问题,使得写操作保证原子性不被其他线程打断,加了ReadWriteLock。

1 packagecom.freud.algorithm.other;2

3 importjava.util.HashMap;4 importjava.util.Map;5 importjava.util.concurrent.TimeUnit;6 importjava.util.concurrent.locks.Lock;7 importjava.util.concurrent.locks.ReentrantLock;8 importjava.util.concurrent.locks.ReentrantReadWriteLock;9

10 /**

11 * 资源类12 */

13 classMyCache {14

15 private volatile Map map = new HashMap<>();16 //传统的Lock不足以满足需求17 //private Lock lock = new ReentrantLock();

18 /**

19 * JUC提供了ReentrantReadWriteLock20 */

21 private ReentrantReadWriteLock rwLock = newReentrantReadWriteLock();22

23 /**

24 * put方法25 *@paramkey26 *@paramvalue27 */

28 public voidput(String key, Object value) {29

30 rwLock.writeLock().lock();31 try{32 System.out.println(Thread.currentThread().getName() + "t 正在写入:" +key);33 //暂停一会儿线程

34 try{35 TimeUnit.MILLISECONDS.sleep(300);36 } catch(InterruptedException e) {37 e.printStackTrace();38 }39 map.put(key, value);40 System.out.println(Thread.currentThread().getName() + "t 写入完成");41 } catch(Exception e) {42 e.printStackTrace();43 } finally{44 rwLock.writeLock().unlock();45 }46 }47

48 /**

49 * get方法50 *@paramkey51 */

52 public voidget(String key) {53

54 rwLock.readLock().lock();55 try{56 System.out.println(Thread.currentThread().getName() + "t 正在读取:");57 //暂停一会儿线程

58 try{59 TimeUnit.MILLISECONDS.sleep(300);60 } catch(InterruptedException e) {61 e.printStackTrace();62 }63 Object value =map.get(key);64 System.out.println(Thread.currentThread().getName() + "t 读取完成:" +value);65 } catch(Exception e) {66 e.printStackTrace();67 } finally{68 rwLock.readLock().unlock();69 }70 }71 }72

73 /**

74 * 多个线程同时读一个资源类没有任何问题,所以为了满足并发量,读取共享资源应该可以同时进行75 * 但是,如果有一个线程想去写共享资源,就不应该再有其他线程可以对这个资源进行读或者写76 * 小总结:77 * 读-读能共存78 * 读-写不能共存79 * 写-写不能共存80 */

81 public classReadWriteLockDemo {82

83 public static voidmain(String[] args) {84

85 MyCache myCache = newMyCache();86

87 for (int i = 0; i < 5; i++) {88 final int tempInt =i;89 new Thread(() ->{90 myCache.put(tempInt + "", tempInt + "");91 }, String.valueOf(i)).start();92 }93

94 for (int i = 0; i < 5; i++) {95 final int tempInt =i;96 new Thread(() ->{97 myCache.get(tempInt + "");98 }, String.valueOf(i)).start();99 }100 }101 }

打印:

"C:Program FilesJavajdk1.8.0_191binjava" "-javaagent:E:JetbrainsIntellijIDEAIntelliJ IDEA 2017.2.6libidea_rt.jar=18187:E:JetbrainsIntellijIDEAIntelliJ IDEA 2017.2.6bin" -Dfile.encoding=UTF-8 -classpath "C:Program FilesJavajdk1.8.0_191jrelibcharsets.jar;C:Program FilesJavajdk1.8.0_191jrelibdeploy.jar;C:Program FilesJavajdk1.8.0_191jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.8.0_191jrelibextcldrdata.jar;C:Program FilesJavajdk1.8.0_191jrelibextdnsns.jar;C:Program FilesJavajdk1.8.0_191jrelibextjaccess.jar;C:Program FilesJavajdk1.8.0_191jrelibextjfxrt.jar;C:Program FilesJavajdk1.8.0_191jrelibextlocaledata.jar;C:Program FilesJavajdk1.8.0_191jrelibextnashorn.jar;C:Program FilesJavajdk1.8.0_191jrelibextsunec.jar;C:Program FilesJavajdk1.8.0_191jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.8.0_191jrelibextsunmscapi.jar;C:Program FilesJavajdk1.8.0_191jrelibextsunpkcs11.jar;C:Program FilesJavajdk1.8.0_191jrelibextzipfs.jar;C:Program FilesJavajdk1.8.0_191jrelibjavaws.jar;C:Program FilesJavajdk1.8.0_191jrelibjce.jar;C:Program FilesJavajdk1.8.0_191jrelibjfr.jar;C:Program FilesJavajdk1.8.0_191jrelibjfxswt.jar;C:Program FilesJavajdk1.8.0_191jrelibjsse.jar;C:Program FilesJavajdk1.8.0_191jrelibmanagement-agent.jar;C:Program FilesJavajdk1.8.0_191jrelibplugin.jar;C:Program FilesJavajdk1.8.0_191jrelibresources.jar;C:Program FilesJavajdk1.8.0_191jrelibrt.jar;E:practisealgorithmoutproductionalgorithm"com.freud.algorithm.other.ReadWriteLockDemo0 正在写入:0

0写入完成1 正在写入:1

1写入完成2 正在写入:2

2写入完成3 正在写入:3

3写入完成4 正在写入:4

4写入完成1正在读取:0正在读取:3正在读取:4正在读取:2正在读取:2 读取完成:2

4 读取完成:4

3 读取完成:3

0 读取完成:0

1 读取完成:1Process finished with exit code0

### Java读写锁与互斥的区别及用法 #### 一、概念对比 读写锁(`ReadWriteLock`),也称为『共享-独占』,其核心特性在于实现了 **读共享,写独占** 的机制[^1]。这意味着多个线程能够并发地进行读操作而不会相互干扰;然而,在任何时间点上仅允许一个线程持有写权限,并且此时不允许其他任何形式的访问。 相比之下,互斥(Mutex Lock 或 `ReentrantLock` 类型)提供了一种更严格的控制方式——即无论是读还是写的请求都必须排队等候当前定资源的操作完成之后才能继续执行。换句话说,它并不区分具体的访问模式而是简单粗暴地阻止一切竞争性的尝试直至前序任务结束并释放该对象上的所有权[^4]。 #### 二、适用场景分析 对于那些频繁发生读取动作但更新相对较少的数据结构来说,采用读写锁无疑更加高效合理。因为在这种情况下,大部分时间内都可以让尽可能多的工作单元同时获取到所需的信息而不必担心同步问题所带来的额外开销。例如在一个大型网站的应用程序中维护用户配置文件副本时就非常适合运用此类策略来优化性能表现。 另一方面,如果业务逻辑涉及到大量修改或者存在高度不确定性的交互流程,则可能更适合选用传统的互斥方案以确保绝对的安全性和一致性。比如银行转账系统中的账户余额调整过程就需要严格遵循串行化原则从而杜绝潜在的风险隐患。 #### 三、具体实现案例展示 下面给出一段基于 `ReentrantReadWriteLock` 实现简易缓存功能的例子: ```java import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class Cache<K, V> { private final ReadWriteLock lock = new ReentrantReadWriteLock(); public void put(K key, V value){ lock.writeLock().lock(); // 获取写 try{ System.out.println(Thread.currentThread().getName()+" write 操作执行"); // 执行实际存储操作... }finally{ lock.writeLock().unlock(); // 解除写 } } @SuppressWarnings("unchecked") public V get(K key){ lock.readLock().lock(); // 获取读 try{ // 返回查询结果... return (V)"模拟返回值"; }finally{ lock.readLock().unlock(); // 解除读 } } } ``` 值得注意的是,上述代码片段展示了如何利用读写锁构建一个多线程安全的缓存组件。其中特别强调了读无法创建条件变量的事实,这表明在设计阶段应当充分考虑到这一点以免造成不必要的麻烦[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值