1、 简介
Lock是java.util.concurrent.locks包下的一个接口。
Lock接口规定了如下方法:
- lock():获取锁。如果锁不可用,那么线程调度目的,当前线程将被禁用并处于休眠状态,直到获取锁为止。
- lockInterruptibly():如果当前线程未被中断,则获取锁;
- tryLock():只有在调用时,锁是空闲的,才获取锁。如果可用,则获取锁并立即返回true,如果锁不可用,则立即返回false;
- tryLock(long TimeUnit):如果锁在给定的等待时间内空闲,且当前线程未被中断,则获取锁;
- unlock():释放锁。在等待条件前,锁必须由当前线程保持。如果调用了Condition.await(),将在等待前以原子方式释放锁,并在等待返回前,重新获取锁。
- newCOndition():返回绑定到此Lock实例的新Condition实例;
它具有如下功能/优势:
- Lock方式来获取锁支持中断、超时不获取、是非阻塞的
- 提高了语义化,哪里加锁,哪里解锁都得写出来;
- Lock显示锁可以给我们带来很好的灵活性,或者说锁的粒度更细,但是同时我们必须手动释放锁;
- 支持Condition条件对象;
- 允许多个读线程同时访问共享资源;
Lock接口下,有如下实现类:
可以看到,除了ReentrantLock外,其他实现类都是位于其他类的内部,我们使用Lock接口的显示锁,其实主要是使用ReentrantLock。
2、ReentrantLock例子及知识点
下面两个例子中,用ReentrantLock代替synchronized,用Condition.await()和Condition.signal()代替Object.wait()和Object.notify()。
package com.atguigu.sh.juc.study01;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/**** 【第二节】** 题目:* 两个线程,可以操作初始值为0的一个变量;* 要求实现一个线程对该变量+1,另一个线程对该变量-1,交替进行,进行10轮** ->* 1. 高耦合第内聚的前提下,线程操作资源类* 2. 判断/干活/通知* 3. 多线程交互中,必须要防止多线程的虚假唤醒,也即(多线程的判断中,不可以用if,只可以用while)* 4. -->请去本包下 ThreadOrderAccess 类下查看*** @author yuanhai* @date 2022年04月23日*/// 资源类class AirConditioner {private int number = 0;private Lock lock = new ReentrantLock();private Condition condition = lock.newCondition();public void increment () {lock.lock();try {// 1. 判断while (number != 0) {condition.await(); // this.wait();}// 2.干活number ++;System.out.println(Thread.currentThread().getName()+"\t"+number);// 3.通知condition.signalAll(); // this.notifyAll();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void decrement () {lock.lock();try {// 1. 判断while (number == 0) {condition.await(); // this.wait();}// 2.干活number--;System.out.println(Thread.currentThread().getName()+"\t"+number);// 3.通知condition.signalAll(); // this.notifyAll();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}// public synchronized void increment () throws InterruptedException {// // 1. 判断// while (number != 0) {// this.wait(); // wait()会停下线程,同时释放锁,把控制权交出去// }// // 2.干活// number ++;// System.out.println(Thread.currentThread().getName()+"\t"+number);// // 3.通知// this.notifyAll();// }//// public synchronized void decrement () throws InterruptedException {// // 1. 判断// while (number == 0) {// this.wait(); // wait会停下线程,同时释放锁,把控制权交出去// }// // 2.干活// number--;// System.out.println(Thread.currentThread().getName()+"\t"+number);// // 3.通知// this.notifyAll();// }}public class ThreadWaitNotifyDemo {public static void main(String[] args) {AirConditioner airConditioner = new AirConditioner();new Thread(() -> {for (int i = 1; i <= 10; i++) {try {Thread.sleep(400);airConditioner.increment();} catch (InterruptedException e) {e.printStackTrace();}}}, "A").start();new Thread(() -> {for (int i = 1; i <= 10; i++) {try {Thread.sleep(500);airConditioner.decrement();} catch (InterruptedException e) {e.printStackTrace();}}}, "B").start();new Thread(() -> {for (int i = 1; i <= 10; i++) {try {Thread.sleep(400);airConditioner.increment();} catch (InterruptedException e) {e.printStackTrace();}}}, "C").start();new Thread(() -> {for (int i = 1; i <= 10; i++) {try {Thread.sleep(500);airConditioner.decrement();} catch (InterruptedException e) {e.printStackTrace();}}}, "D").start();}}
