ReentantLock 继承接口Lock 并实现了接口中定义的方法,他是一种可重入锁,除了能完成synchronized 所能完成的所有工作外,还提供了诸如可响应中断锁、可轮询锁请求、定时锁等避免多线程死锁的方法。
Lock 接口的主要方法
- void lock(): 执行此方法时, 如果锁处于空闲状态, 当前线程将获取到锁. 相反, 如果锁已经被其他线程持有, 将禁用当前线程, 直到当前线程获取到锁.
- boolean tryLock():如果锁可用, 则获取锁, 并立即返回true, 否则返回false. 该方法和lock()的区别在于, tryLock()只是"试图"获取锁, 如果锁不可用, 不会导致当前线程被禁用,当前线程仍然继续往下执行代码. 而lock()方法则是一定要获取到锁, 如果锁不可用, 就一直等待, 在未获得锁之前,当前线程并不继续向下执行.
- void unlock():执行此方法时, 当前线程将释放持有的锁. 锁只能由持有者释放, 如果线程并不持有锁, 却执行该方法, 可能导致异常的发生.
- Condition newCondition():条件对象,获取等待通知组件。该组件和当前的锁绑定,当前线程只有获取了锁,才能调用该组件的await()方法,而调用后,当前线程将缩放锁。
- getHoldCount() :查询当前线程保持此锁的次数,也就是执行此线程执行lock 方法的次数。
- getQueueLength():返回正等待获取此锁的线程估计数,比如启动10 个线程,1 个线程获得锁,此时返回的是9
- getWaitQueueLength:(Condition condition)返回等待与此锁相关的给定条件的线程估计数。比如10 个线程,用同一个condition 对象,并且此时这10 个线程都执行了condition 对象的await 方法,那么此时执行此方法返回10
- hasWaiters(Condition condition) : 查询是否有线程等待与此锁有关的给定条件(condition),对于指定contidion 对象,有多少线程执行了condition.await 方法
- hasQueuedThread(Thread thread):查询给定线程是否等待获取此锁
- hasQueuedThreads():是否有线程等待此锁
- isFair():该锁是否公平锁
- isHeldByCurrentThread(): 当前线程是否保持锁锁定,线程的执行lock 方法的前后分别是false 和true
- isLock():此锁是否有任意线程占用
- lockInterruptibly():如果当前线程未被中断,获取锁
- tryLock():尝试获得锁,仅在调用时锁未被线程占用,获得锁
- tryLock(long timeout TimeUnit unit):如果锁在给定等待时间内没有被另一个线程保持,
则获取该锁。
非公平锁
JVM 按随机、就近原则分配锁的机制则称为不公平锁,ReentrantLock 在构造函数中提供了是否公平锁的初始化方式,默认为非公平锁。非公平锁实际执行的效率要远远超出公平锁,除非程序有特殊需要,否则最常用非公平锁的分配机制。
公平锁
公平锁指的是锁的分配机制是公平的,通常先对锁提出获取请求的线程会先被分配到锁,ReentrantLock 在构造函数中提供了是否公平锁的初始化方式来定义公平锁。
ReentrantLock与synchronized对比
- ReentrantLock 通过方法lock()与unlock()来进行加锁与解锁操作,与synchronized 会被JVM 自动解锁机制不同,ReentrantLock 加锁后需要手动进行解锁。为了避免程序出现异常而无法正常解锁的情况,使用ReentrantLock 必须在finally 控制块中进行解锁操作。
- ReentrantLock 相比synchronized 的优势是可中断、公平锁、多个锁。这种情况下需要使用ReentrantLock。
ReentrantLock的实现
public class MyService {
private Lock lock = new ReentrantLock();
//Lock lock=new ReentrantLock(true);//公平锁
//Lock lock=new ReentrantLock(false);//非公平锁
private Condition condition=lock.newCondition();//创建Condition
public void testMethod() {
try {
lock.lock();//lock 加锁
//1:wait 方法等待:
//System.out.println("开始wait");
condition.await();
//通过创建Condition 对象来使线程wait,必须先执行lock.lock 方法获得锁
//:2:signal 方法唤醒
condition.signal();//condition 对象的signal 方法可以唤醒wait 线程
for (int i = 0; i < 5; i++) {
System.out.println("ThreadName=" + Thread.currentThread().getName()+ (" " + (i + 1)));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
finally
13/04/2018 Page 68 of 283
{
lock.unlock();
}
}
Condition 类Object类的锁方法区别
- Condition 类的awiat 方法和Object 类的wait 方法等效
- Condition 类的signal 方法和Object 类的notify 方法等效
- Condition 类的signalAll 方法和Object 类的notifyAll 方法等效
- ReentrantLock 类可以唤醒指定条件的线程,而object 的唤醒是随机的
tryLock和lock和lockInterruptibly的区别
- tryLock 能获得锁就返回true,不能就立即返回false,tryLock(long timeout,TimeUnit unit),可以增加时间限制,如果超过该时间段还没获得锁,返回false
- lock 能获得锁就返回true,不能的话一直等待获得锁
- lock 和lockInterruptibly,如果两个线程分别执行这两个方法,但此时中断这两个线程,lock 不会抛出异常,而lockInterruptibly 会抛出异常。
网友评论