1、 简介

Lock是java.util.concurrent.locks包下的一个接口。
Lock接口规定了如下方法:
image.png

  • lock():获取锁。如果锁不可用,那么线程调度目的,当前线程将被禁用并处于休眠状态,直到获取锁为止。
  • lockInterruptibly():如果当前线程未被中断,则获取锁;
  • tryLock():只有在调用时,锁是空闲的,才获取锁。如果可用,则获取锁并立即返回true,如果锁不可用,则立即返回false;
  • tryLock(long TimeUnit):如果锁在给定的等待时间内空闲,且当前线程未被中断,则获取锁;
  • unlock():释放锁。在等待条件前,锁必须由当前线程保持。如果调用了Condition.await(),将在等待前以原子方式释放锁,并在等待返回前,重新获取锁。
  • newCOndition():返回绑定到此Lock实例的新Condition实例;

它具有如下功能/优势:

  • Lock方式来获取锁支持中断、超时不获取、是非阻塞的
  • 提高了语义化,哪里加锁,哪里解锁都得写出来;
  • Lock显示锁可以给我们带来很好的灵活性,或者说锁的粒度更细,但是同时我们必须手动释放锁;
  • 支持Condition条件对象;
  • 允许多个读线程同时访问共享资源;

Lock接口下,有如下实现类:
image.png
可以看到,除了ReentrantLock外,其他实现类都是位于其他类的内部,我们使用Lock接口的显示锁,其实主要是使用ReentrantLock。

2、ReentrantLock例子及知识点

下面两个例子中,用ReentrantLock代替synchronized,用Condition.await()和Condition.signal()代替Object.wait()和Object.notify()。

  1. package com.atguigu.sh.juc.study01;
  2. import java.util.concurrent.locks.Condition;
  3. import java.util.concurrent.locks.Lock;
  4. import java.util.concurrent.locks.ReentrantLock;
  5. /**
  6. *
  7. * 【第二节】
  8. *
  9. * 题目:
  10. * 两个线程,可以操作初始值为0的一个变量;
  11. * 要求实现一个线程对该变量+1,另一个线程对该变量-1,交替进行,进行10轮
  12. *
  13. * ->
  14. * 1. 高耦合第内聚的前提下,线程操作资源类
  15. * 2. 判断/干活/通知
  16. * 3. 多线程交互中,必须要防止多线程的虚假唤醒,也即(多线程的判断中,不可以用if,只可以用while)
  17. * 4. -->请去本包下 ThreadOrderAccess 类下查看
  18. *
  19. *
  20. * @author yuanhai
  21. * @date 2022年04月23日
  22. */
  23. // 资源类
  24. class AirConditioner {
  25. private int number = 0;
  26. private Lock lock = new ReentrantLock();
  27. private Condition condition = lock.newCondition();
  28. public void increment () {
  29. lock.lock();
  30. try {
  31. // 1. 判断
  32. while (number != 0) {
  33. condition.await(); // this.wait();
  34. }
  35. // 2.干活
  36. number ++;
  37. System.out.println(Thread.currentThread().getName()+"\t"+number);
  38. // 3.通知
  39. condition.signalAll(); // this.notifyAll();
  40. } catch (Exception e) {
  41. e.printStackTrace();
  42. } finally {
  43. lock.unlock();
  44. }
  45. }
  46. public void decrement () {
  47. lock.lock();
  48. try {
  49. // 1. 判断
  50. while (number == 0) {
  51. condition.await(); // this.wait();
  52. }
  53. // 2.干活
  54. number--;
  55. System.out.println(Thread.currentThread().getName()+"\t"+number);
  56. // 3.通知
  57. condition.signalAll(); // this.notifyAll();
  58. } catch (Exception e) {
  59. e.printStackTrace();
  60. } finally {
  61. lock.unlock();
  62. }
  63. }
  64. // public synchronized void increment () throws InterruptedException {
  65. // // 1. 判断
  66. // while (number != 0) {
  67. // this.wait(); // wait()会停下线程,同时释放锁,把控制权交出去
  68. // }
  69. // // 2.干活
  70. // number ++;
  71. // System.out.println(Thread.currentThread().getName()+"\t"+number);
  72. // // 3.通知
  73. // this.notifyAll();
  74. // }
  75. //
  76. // public synchronized void decrement () throws InterruptedException {
  77. // // 1. 判断
  78. // while (number == 0) {
  79. // this.wait(); // wait会停下线程,同时释放锁,把控制权交出去
  80. // }
  81. // // 2.干活
  82. // number--;
  83. // System.out.println(Thread.currentThread().getName()+"\t"+number);
  84. // // 3.通知
  85. // this.notifyAll();
  86. // }
  87. }
  88. public class ThreadWaitNotifyDemo {
  89. public static void main(String[] args) {
  90. AirConditioner airConditioner = new AirConditioner();
  91. new Thread(() -> {
  92. for (int i = 1; i <= 10; i++) {
  93. try {
  94. Thread.sleep(400);
  95. airConditioner.increment();
  96. } catch (InterruptedException e) {
  97. e.printStackTrace();
  98. }
  99. }
  100. }, "A").start();
  101. new Thread(() -> {
  102. for (int i = 1; i <= 10; i++) {
  103. try {
  104. Thread.sleep(500);
  105. airConditioner.decrement();
  106. } catch (InterruptedException e) {
  107. e.printStackTrace();
  108. }
  109. }
  110. }, "B").start();
  111. new Thread(() -> {
  112. for (int i = 1; i <= 10; i++) {
  113. try {
  114. Thread.sleep(400);
  115. airConditioner.increment();
  116. } catch (InterruptedException e) {
  117. e.printStackTrace();
  118. }
  119. }
  120. }, "C").start();
  121. new Thread(() -> {
  122. for (int i = 1; i <= 10; i++) {
  123. try {
  124. Thread.sleep(500);
  125. airConditioner.decrement();
  126. } catch (InterruptedException e) {
  127. e.printStackTrace();
  128. }
  129. }
  130. }, "D").start();
  131. }
  132. }