并发类编程—ReentrantLock(可重入锁)
1、概念
ReentantLock继承接口 Lock 并实现了接口中定义的方法,他是一种可重入锁,除了能完成synchronized 所能完成的所有工作外,还提供了中断锁、定时锁等避免多线程死锁的方法。
ReentantLock可以创建多个Condition条件,通过await()和signal()方法实现等待和唤醒。
2、主要方法
- void lock(): 执行此方法时, 如果锁处于空闲状态, 当前线程将获取到锁. 相反, 如果锁已经被其他线程持有, 将一直等待直到当前线程获取到锁.
- boolean tryLock():如果锁可用, 则获取锁, 并立即返回 true, 否则返回 false. 该方法和
lock()的区别在于, tryLock()只是"试图"获取锁, 如果锁不可用, 不会导致当前线程被挂起,当前线程仍然继续往下执行代码. - void unlock():当前线程将释放持有的锁. 锁只能由持有线程释放.
- getHoldCount() :查询当前线程保持此锁的次数,也就是执行此线程执行lock方法的次数。
- getQueueLength():返回正等待获取此锁的线程估计数,比如启动 10 个线程,1 个线程获得锁,此时返回的是 9.
- hasQueuedThread(Thread thread):查询给定线程是否等待获取此锁
- hasQueuedThreads():是否有线程等待此锁
- isFair():该锁是否公平锁
- isLock():此锁是否有任意线程占用
- lockInterruptibly():如果当前线程未被中断,获取锁
- tryLock(long timeout TimeUnit unit):在给定等待时间内尝试获取锁,获取获得到则返回true,没有获取则返回flase.
3、Condition使用
Condition用时等待/通知,即当线程进行等待后,需要通知才能继续执行。
await()进入等待,signal()唤醒绑定Condition的第一个线程,signalAll()唤醒绑定Condition的所有线程。
比如: A、B两个线程轮流打印数字
public class Test { public static void main(String[] args) { Lock lock = new ReentrantLock(); Condition conditionA = lock.newCondition(); Condition conditionB = lock.newCondition(); new Thread(() -> { try { for (int a = 1; a <= 10; a++) { // 上锁 lock.lock(); System.out.println("线程A打印数字:" + a); // 唤醒其他线程 conditionB.signalAll(); // 自身进入等待状态 conditionA.await(); } } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } }, "conditionA").start(); new Thread(() -> { try { for (int a = 1; a <= 10; a++) { // 上锁 lock.lock(); System.out.println("线程B打印数字:" + a); // 唤醒其他线程 conditionA.signalAll(); // 自身进入等待状态 conditionB.await(); } } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } }, "conditionB").start(); }}
效果: