ReentrantLock

相对于synchronized的特点
  1. 1.可中断
  2. 2.可以设置超时时间
  3. 3.可以设置为公平锁 (防止线程饥饿)
  4. 4.支持多个条件变量
  5. 5.synchronized一样,都支持可重入
  1. // 获取锁
  2. reentrantLock.lock();
  3. try {
  4. // 临界区
  5. } finally {
  6. // 释放锁
  7. reentrantLock.unlock();
  8. }

可重入:

可重入是指同一个线程如果首次获得了这把锁,那么因为它是这把锁的拥有者,因此有权利再次获得这把锁,

如果是不可重入锁,那么第二次获得锁时,自己也会被锁挡住

可打断:

在等待锁的过程中,其他线程使用interrupt方法打断。则获取锁的类型为

reentrantLock.lockInterruptibly

锁超时:

tryLock()——尝试获得锁———参数可以为时间和单位,在指定时间之内获取不到锁就放弃

该方法同样可以被打断

公平锁:(一般情况下没有必要,会降低并发度)

ReentrantLock默认是不公平的(随机获取而不是按照进入阻塞队列的顺序来获取锁资源)

条件变量:

synchronized 中也有条件变量,就是我们讲原理时那个 waitSet 休息室,当条件不满足时进入 waitSet 等待

ReentrantLock 的条件变量比 synchronized 强大之处在于,它是支持多个条件变量的,这就好比

  1. synchronized 是那些不满足条件的线程都在一间休息室等消息
  2. ReentrantLock 支持多间休息室,有专门等烟的休息室、专门等早餐的休息室、唤醒时也是按休息室来唤醒

使用newCondition()方法来创建多个休息室

使用要点:

  1. await 前需要获得锁
  2. await 执行后,会释放锁,进入 conditionObject 等待
  3. await 的线程被唤醒(或打断、或超时)取重新竞争 lock
  4. 竞争 lock 锁成功后,从 await 后继续执行

await相当于wait,signal相当于notify

补充

由于ReentrantLock是java.util.concurrent包下提供的一套互斥锁,相比Synchronized,ReentrantLock类提供了一些高级功能,主要有以下3项:

1.等待可中断

持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。通过lock.lockInterruptibly()来实现这个机制。

2.公平锁

多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。

公平锁、非公平锁的创建方式:

创建一个非公平锁,默认是非公平锁Lock lock = new ReentrantLock();Lock lock = new ReentrantLock(false);
创建一个公平锁,构造传参trueLock lock = new ReentrantLock(true);

3.锁绑定多个条件

一个ReentrantLock对象可以同时绑定对个对象。ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。