简述
ReentrantLock 是一个可重入的互斥(/独占)锁,又称为“独占锁”。
ReentrantLock通过自定义队列同步器(AQS-AbstractQueuedSychronized,是实现锁的关键)来实现锁的获取与释放。
其可以完全替代 synchronized 关键字。JDK 5.0 早期版本,其性能远好于 synchronized,但 JDK 6.0 开始,JDK 对 synchronized 做了大量的优化,使得两者差距并不大。
“独占”,就是在同一时刻只能有一个线程获取到锁,而其它获取锁的线程只能处于同步队列中等待,只有获取锁的线程释放了锁,后继的线程才能够获取锁。
“可重入”,就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁。
该锁还支持获取锁时的公平和非公平性选择。“公平”是指“不同的线程获取锁的机制是公平的”,而“不公平”是指“不同的线程获取锁的机制是非公平的”。
简单实例
importjava.util.concurrent.locks.ReentrantLock;/*** Created by zhengbinMac on 2017/3/2.*/
public class ReenterLock implementsRunnable{public static ReentrantLock lock = newReentrantLock();public static int i = 0;public voidrun() {for (int j = 0;j<100000;j++) {
lock.lock();//lock.lock();
try{
i++;
}finally{
lock.unlock();//lock.unlock();
}
}
}public static void main(String[] args) throwsInterruptedException {
ReenterLock reenterLock= newReenterLock();
Thread t1= newThread(reenterLock);
Thread t2= newThread(reenterLock);
t1.start();t2.start();
t1.join();t2.join();
System.out.println(i);
}
}
与 synchronized 相比,重入锁有着显示的操作过程,何时加锁,何时释放,都在程序员的控制中。
为什么称作是“重入”?这是因为这种锁是可以反复进入的。将上面代码中注释部分去除注释,也就是连续两次获得同一把锁,两次释放同一把锁,这是允许的。
注意,获得锁次数与释放锁次数要相同,如果释放锁次数多了,会抛出 java.lang.IllegalMonitorStateException 异常;如果释放次数少了,相当于线程还持有这个锁,其他线程就无法进入临界区。
引出第一个问题:为什么 ReentrantLock 锁能够支持一个线程对资源的重复加锁?
除了简单的加锁、解锁操作,重入锁还提供了一些更高级的功能,下面结合实例进行简单介绍:
中断响应(lockInterruptibly)
对于 synchronized 来说,如果一个线程在等待锁,那么结果只有两种情况,获得这把锁继续执行,或者线程就保持等待。
而使用重入锁,提供了另一种可能,这就是线程可以被中断。也就是在等待锁的过程中,程序可以根据需要取消对锁的需求。
下面的例子中,产生了死锁,但得益于锁中断,最终解决了这个死锁: