Java锁_读写锁

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

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

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

 

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

 1 package com.freud.algorithm.other;
 2 
 3 import java.util.HashMap;
 4 import java.util.Map;
 5 import java.util.concurrent.TimeUnit;
 6 import java.util.concurrent.locks.Lock;
 7 import java.util.concurrent.locks.ReentrantLock;
 8 
 9 /**
10  * 资源类
11  */
12 class MyCache {
13 
14     private volatile Map<String, Object> map = new HashMap<>();
15     // private Lock lock = new ReentrantLock();
16     public void put(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 void get(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 class ReadWriteLockDemo {
52 
53     public static void main(String[] args) {
54 
55         MyCache myCache = new MyCache();
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 Files\Java\jdk1.8.0_191\bin\java" "-javaagent:E:\Jetbrains\IntellijIDEA\IntelliJ IDEA 2017.2.6\lib\idea_rt.jar=12592:E:\Jetbrains\IntellijIDEA\IntelliJ IDEA 2017.2.6\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_191\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\rt.jar;E:\practise\algorithm\out\production\algorithm" com.freud.algorithm.other.ReadWriteLockDemo
 2 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 package com.freud.algorithm.other;
  2 
  3 import java.util.HashMap;
  4 import java.util.Map;
  5 import java.util.concurrent.TimeUnit;
  6 import java.util.concurrent.locks.Lock;
  7 import java.util.concurrent.locks.ReentrantLock;
  8 import java.util.concurrent.locks.ReentrantReadWriteLock;
  9 
 10 /**
 11  * 资源类
 12  */
 13 class MyCache {
 14 
 15     private volatile Map<String, Object> map = new HashMap<>();
 16     // 传统的Lock不足以满足需求
 17     // private Lock lock = new ReentrantLock();
 18     /**
 19      * JUC提供了ReentrantReadWriteLock
 20      */
 21     private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
 22 
 23     /**
 24      * put方法
 25      * @param key
 26      * @param value
 27      */
 28     public void put(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      * @param key
 51      */
 52     public void get(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 class ReadWriteLockDemo {
 82 
 83     public static void main(String[] args) {
 84 
 85         MyCache myCache = new MyCache();
 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 Files\Java\jdk1.8.0_191\bin\java" "-javaagent:E:\Jetbrains\IntellijIDEA\IntelliJ IDEA 2017.2.6\lib\idea_rt.jar=18187:E:\Jetbrains\IntellijIDEA\IntelliJ IDEA 2017.2.6\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_191\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\rt.jar;E:\practise\algorithm\out\production\algorithm" com.freud.algorithm.other.ReadWriteLockDemo
0     正在写入: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     读取完成:1

Process finished with exit code 0

 

posted @ 2020-07-30 13:50  Freud领工资也用券  阅读(256)  评论(0编辑  收藏  举报