架构师养成记--14.重入锁ReentrantLock 和 读写锁 ReentrantReadWriteLock

Posted 司广孟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了架构师养成记--14.重入锁ReentrantLock 和 读写锁 ReentrantReadWriteLock相关的知识,希望对你有一定的参考价值。

ReentrantLock

有嗅探锁定和多路分支等功能,其实就是synchronized,wait,notify的升级。

this锁定当前对象不方便,于是就有了用new Object()来作为锁的解决方案,后面jdk干脆就提供了一个Lock类。

 

伪代码:

Lock lock = new ReentrantLock();//新建一个lock

Condition condition = lock.newCondition();//获取条件

method1(){

  try{

    lock.lock();

    代码块;

    lock.unlock();

    后续代码块;

  }

}

method2(){

  try{

    lock.lock();

    代码块;

    lock.signal();

  }

}

 

单condition操作:

 1 import java.util.concurrent.locks.Condition;
 2 import java.util.concurrent.locks.Lock;
 3 import java.util.concurrent.locks.ReentrantLock;
 4 
 5 public class UseCondition {
 6 
 7     private Lock lock = new ReentrantLock();
 8     private Condition condition = lock.newCondition();
 9     
10     public void method1(){
11         try {
12             lock.lock();
13             System.out.println("当前线程:" + Thread.currentThread().getName() + "进入..");
14             Thread.sleep(3000);
15             System.out.println("当前线程:" + Thread.currentThread().getName() + "释放锁..");
16             condition.await();    // Object wait
17             System.out.println("当前线程:" + Thread.currentThread().getName() +"继续执行...");
18         } catch (Exception e) {
19             e.printStackTrace();
20         } finally {
21             lock.unlock();
22         }
23     }
24     
25     public void method2(){
26         try {
27             lock.lock();
28             System.out.println("当前线程:" + Thread.currentThread().getName() + "进入..");
29             Thread.sleep(3000);
30             System.out.println("当前线程:" + Thread.currentThread().getName() + "发出唤醒..");
31             condition.signal();        //Object notify
32         } catch (Exception e) {
33             e.printStackTrace();
34         } finally {
35             lock.unlock();
36         }
37     }
38     
39     public static void main(String[] args) {
40         
41         final UseCondition uc = new UseCondition();
42         Thread t1 = new Thread(new Runnable() {
43             @Override
44             public void run() {
45                 uc.method1();
46             }
47         }, "t1");
48         Thread t2 = new Thread(new Runnable() {
49             @Override
50             public void run() {
51                 uc.method2();
52             }
53         }, "t2");
54         t1.start();
55 
56         t2.start();
57     }
58     
59     
60     
61 }

执行结果:

 
解释:线程1调用method1方法,线程2调用同一对象的method2方法,线程1先启动,线程1获取锁,进入method1的代码块,线程2也启动了,单是线程2被锁定,直到线程1发出lock.unlock()了,线程1才将锁释放,这时线程2获取锁,执行method2的代码块,线程2发出lock.signal(); 线程1才继续执行后续代码块。

 多condition操作:

  1 import java.util.concurrent.locks.Condition;
  2 import java.util.concurrent.locks.ReentrantLock;
  3 
  4 public class UseManyCondition {
  5 
  6     private ReentrantLock lock = new ReentrantLock();
  7     private Condition c1 = lock.newCondition();
  8     private Condition c2 = lock.newCondition();
  9     
 10     public void m1(){
 11         try {
 12             lock.lock();
 13             System.out.println("当前线程:" +Thread.currentThread().getName() + "进入方法m1等待..");
 14             c1.await();
 15             System.out.println("当前线程:" +Thread.currentThread().getName() + "方法m1继续..");
 16         } catch (Exception e) {
 17             e.printStackTrace();
 18         } finally {
 19             lock.unlock();
 20         }
 21     }
 22     
 23     public void m2(){
 24         try {
 25             lock.lock();
 26             System.out.println("当前线程:" +Thread.currentThread().getName() + "进入方法m2等待..");
 27             c1.await();
 28             System.out.println("当前线程:" +Thread.currentThread().getName() + "方法m2继续..");
 29         } catch (Exception e) {
 30             e.printStackTrace();
 31         } finally {
 32             lock.unlock();
 33         }
 34     }
 35     
 36     public void m3(){
 37         try {
 38             lock.lock();
 39             System.out.println("当前线程:" +Thread.currentThread().getName() + "进入方法m3等待..");
 40             c2.await();
 41             System.out.println("当前线程:" +Thread.currentThread().getName() + "方法m3继续..");
 42         } catch (Exception e) {
 43             e.printStackTrace();
 44         } finally {
 45             lock.unlock();
 46         }
 47     }
 48     
 49     public void m4(){
 50         try {
 51             lock.lock();
 52             System.out.println("当前线程:" +Thread.currentThread().getName() + "唤醒..");
 53             c1.signalAll();
 54         } catch (Exception e) {
 55             e.printStackTrace();
 56         } finally {
 57             lock.unlock();
 58         }
 59     }
 60     
 61     public void m5(){
 62         try {
 63             lock.lock();
 64             System.out.println("当前线程:" +Thread.currentThread().getName() + "唤醒..");
 65             c2.signal();
 66         } catch (Exception e) {
 67             e.printStackTrace();
 68         } finally {
 69             lock.unlock();
 70         }
 71     }
 72     
 73     public static void main(String[] args) {
 74         
 75         
 76         final UseManyCondition umc = new UseManyCondition();
 77         Thread t1 = new Thread(new Runnable() {
 78             @Override
 79             public void run() {
 80                 umc.m1();
 81             }
 82         },"t1");
 83         Thread t2 = new Thread(new Runnable() {
 84             @Override
 85             public void run() {
 86                 umc.m2();
 87             }
 88         },"t2");
 89         Thread t3 = new Thread(new Runnable() {
 90             @Override
 91             public void run() {
 92                 umc.m3();
 93             }
 94         },"t3");
 95         Thread t4 = new Thread(new Runnable() {
 96             @Override
 97             public void run() {
 98                 umc.m4();
 99             }
100         },"t4");
101         Thread t5 = new Thread(new Runnable() {
102             @Override
103             public void run() {
104                 umc.m5();
105             }
106         },"t5");
107         
108         t1.start();    // c1
109         t2.start();    // c1
110         t3.start();    // c2
111         
112 
113         try {
114             Thread.sleep(2000);
115         } catch (InterruptedException e) {
116             e.printStackTrace();
117         }
118 
119         t4.start();    // c1
120         try {
121             Thread.sleep(2000);
122         } catch (InterruptedException e) {
123             e.printStackTrace();
124         }
125         t5.start();    // c2
126         
127     }
128     
129     
130     
131 }

执行结果:

解释:t1、t2线程都是用第一个condition c1,t3线程用第二个condition c2,t4线程发出c1.signalAll() 唤醒t1和t2线程,t5发出c2.signal()唤醒t3线程。

 

ReentrantReadWriteLock

读写分离锁,读读共享、写写互斥、读写互斥。

 1 import java.util.concurrent.locks.ReentrantReadWriteLock;
 2 import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
 3 import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
 4 
 5 public class UseReentrantReadWriteLock {
 6 
 7     private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
 8     private ReadLock readLock = rwLock.readLock();
 9     private WriteLock writeLock = rwLock.writeLock();
10     
11     public void read(){
12         try {
13             readLock.lock();
14             System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
15             Thread.sleep(3000);
16             System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
17         } catch (Exception e) {
18             e.printStackTrace();
19         } finally {
20             readLock.unlock();
21         }
22     }
23     
24     public void write(){
25         try {
26             writeLock.lock();
27             System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
28             Thread.sleep(3000);
29             System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
30         } catch (Exception e) {
31             e.printStackTrace();
32         } finally {
33             writeLock.unlock();
34         }
35     }
36     
37     public static void main(String[] args) {
38         
39         final UseReentrantReadWriteLock urrw = new UseReentrantReadWriteLock();
40         
41         Thread t1 = new Thread(new Runnable() {
42             @Override
43             public void run() {
44                 urrw.read();
45             }
46         }, "t1");
47         Thread t2 = new Thread(new Runnable() {
48             @Override
49             public void run() {
50                 urrw.read();
51             }
52         }, "t2");
53         Thread t3 = new Thread(new Runnable() {
54             @Override
55             public void run() {
56                 urrw.write();
57             }
58         }, "t3");
59         Thread t4 = new Thread(new Runnable() {
60             @Override
61             public void run() {
62                 urrw.write();
63             }
64         }, "t4");        
65         
66         t1.start();
67         t2.start();
68         
69 //        t1.start(); // R 
70 //        t3.start(); // W
71         
72 //        t3.start();
73 //        t4.start();
74     }
75 }

解释:t1和t2都是读,是共享的,可同时获得readLock同时进入read方法执行。t1是读和t3是写,是互斥的,只有t1执行完t3才能执行。t3、t4都是写,是互斥的,只有等t3执行完t4才能继续。

以上是关于架构师养成记--14.重入锁ReentrantLock 和 读写锁 ReentrantReadWriteLock的主要内容,如果未能解决你的问题,请参考以下文章

架构师养成记--2脏读

架构师养成记--5.线程之间的通信

架构师养成记--10.master-worker模式

架构师养成记--线程基础

架构师养成记--15.Disruptor并发框架

架构师养成记--6.单例和多线程ThreadLocal