每天一例多线程[day20]-----ReentrantLock

 

ReentrantLock是JDK的并发包下locks包下的工具类,ReentrantLock比synchonized性能要好,但是jdk1.8之后synchonized的性能也得到大幅度提升,不亚于ReentrantLock。

锁的演变

 ReentrantLock是由synchonized和对象锁演变而来。回忆以下之前使用synchronized和Object锁的方式:

 
  1. public void method1(){

  2. synchronized (this) { //对象锁

  3. try {

  4. System.out.println("do method1..");

  5. Thread.sleep(2000);

  6. } catch (InterruptedException e) {

  7. e.printStackTrace();

  8. }

  9. }

  10. }

 
  1. public void method2(){ //类锁

  2. synchronized (ObjectLock.class) {

  3. try {

  4. System.out.println("do method2..");

  5. Thread.sleep(2000);

  6. } catch (InterruptedException e) {

  7. e.printStackTrace();

  8. }

  9. }

  10. }

 
  1. private Object lock = new Object();

  2. public void method3(){ //任何对象锁

  3. synchronized (lock) {

  4. try {

  5. System.out.println("do method3..");

  6. Thread.sleep(2000);

  7. } catch (InterruptedException e) {

  8. e.printStackTrace();

  9. }

  10. }

  11. }

而ReentrantLock的使用则灵活很多:

 
  1. import java.util.concurrent.locks.Lock;

  2. import java.util.concurrent.locks.ReentrantLock;

  3.  
  4. public class UseReentrantLock {

  5.  
  6. private Lock lock = new ReentrantLock();

  7.  
  8. public void method1(){

  9. try {

  10. lock.lock();

  11. System.out.println("当前线程:" + Thread.currentThread().getName() + "进入method1..");

  12. Thread.sleep(1000);

  13. System.out.println("当前线程:" + Thread.currentThread().getName() + "退出method1..");

  14. Thread.sleep(1000);

  15. } catch (InterruptedException e) {

  16. e.printStackTrace();

  17. } finally {

  18. lock.unlock();

  19. }

  20. }

  21.  
  22. public void method2(){

  23. try {

  24. lock.lock();

  25. System.out.println("当前线程:" + Thread.currentThread().getName() + "进入method2..");

  26. Thread.sleep(2000);

  27. System.out.println("当前线程:" + Thread.currentThread().getName() + "退出method2..");

  28. Thread.sleep(1000);

  29. } catch (InterruptedException e) {

  30. e.printStackTrace();

  31. } finally {

  32. lock.unlock();

  33. }

  34. }

  35.  
  36. public static void main(String[] args) {

  37.  
  38. final UseReentrantLock ur = new UseReentrantLock();

  39. Thread t1 = new Thread(new Runnable() {

  40. @Override

  41. public void run() {

  42. ur.method1();

  43. ur.method2();

  44. }

  45. }, "t1");

  46.  
  47. t1.start();

  48. try {

  49. Thread.sleep(10);

  50. } catch (InterruptedException e) {

  51. e.printStackTrace();

  52. }

  53. //System.out.println(ur.lock.getQueueLength());

  54. }

  55.  
  56.  
  57. }

打印:

 
  1. 当前线程:t1进入method1..

  2. 当前线程:t1退出method1..

  3. 当前线程:t1进入method2..

  4. 当前线程:t1退出method2..

分析:我们定义了一个线程t1,在t1中执行method1和method2两个方法,这两个方法都加了ReentrantLock,那么在执行时如果method1先获得lock,就会执行method1的方法,unlock释放锁后,才能进入method2再次获得锁并执行method2,然后释放锁。

 

锁的通信

Object对象的wait和notify必须配合synchonized使用。而ReentrantLock配合Condition使用。

 
  1.  
  2.  
  3. import java.util.concurrent.locks.Condition;

  4. import java.util.concurrent.locks.Lock;

  5. import java.util.concurrent.locks.ReentrantLock;

  6.  
  7.  
  8. public class UseCondition {

  9.  
  10.  
  11. private Lock lock = new ReentrantLock();

  12. private Condition condition = lock.newCondition();

  13.  
  14. public void method1(){

  15. try {

  16. lock.lock();

  17. System.out.println("当前线程:" + Thread.currentThread().getName() + "进入等待状态..");

  18. Thread.sleep(3000);

  19. System.out.println("当前线程:" + Thread.currentThread().getName() + "释放锁..");

  20. condition.await(); //阻塞并释放锁     类似于 Object wait

  21. System.out.println("当前线程:" + Thread.currentThread().getName() +"继续执行...");

  22. } catch (Exception e) {

  23. e.printStackTrace();

  24. } finally {

  25. lock.unlock();

  26. }

  27. }

  28.  
  29. public void method2(){

  30. try {

  31. lock.lock();

  32. System.out.println("当前线程:" + Thread.currentThread().getName() + "进入..");

  33. Thread.sleep(3000);

  34. System.out.println("当前线程:" + Thread.currentThread().getName() + "发出唤醒..");

  35. condition.signal(); //唤醒 不释放锁  类似于Object notify

  36. } catch (Exception e) {

  37. e.printStackTrace();

  38. } finally {

  39. lock.unlock();

  40. }

  41. }

  42.  
  43. public static void main(String[] args) {

  44.  
  45. final UseCondition uc = new UseCondition();

  46. Thread t1 = new Thread(new Runnable() {

  47. @Override

  48. public void run() {

  49. uc.method1();

  50. }

  51. }, "t1");

  52. Thread t2 = new Thread(new Runnable() {

  53. @Override

  54. public void run() {

  55. uc.method2();

  56. }

  57. }, "t2");

  58. t1.start();

  59.  
  60.  
  61. t2.start();

  62. }

  63.  
  64.  
  65.  
  66. }

打印:

 
  1. 当前线程:t1进入等待状态..

  2. 当前线程:t1释放锁..

  3. 当前线程:t2进入..

  4. 当前线程:t2发出唤醒..

  5. 当前线程:t1继续执行...

分析:我们定义t1和t2两个线程,t1执行method1,t2执行method2,t1进入method1后获得lock,进入等待,3s后调用condition.await();释放锁,进入阻塞状态。然后t2线程获得lock,3s后发出唤醒condition.signal();接着t1被唤醒,打印“继续执行...”

 

多Condition

我们可以通过1个lock对象产生多个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. }

分析:定义5个线程:t1、t2、t3、t4、t5,分别执行m1、m2、m3、m4、m5这五个方法。m1和m2都阻塞了c1这个Condition,而m3阻塞的是c2这个Condition,m4中唤醒了c1,m5唤醒了c2,t1和t2跟t3先执行,那么线程t1和t2跟t3都分别被c1和c2阻塞,直到t4唤醒了c1,t1和t2继续执行,t5唤醒了t2,t3继续执行。

打印:

 
  1. 当前线程:t1进入方法m1等待..

  2. 当前线程:t2进入方法m2等待..

  3. 当前线程:t3进入方法m3等待..

  4. 当前线程:t4唤醒..

  5. 当前线程:t1方法m1继续..

  6. 当前线程:t2方法m2继续..

  7. 当前线程:t5唤醒..

  8. 当前线程:t3方法m3继续..

 

 了解:ReentrantLock默认非公平,性能比公平锁要高

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值