3.8 ReentrandLock
故名思意,ReentrandLock即可重入锁。可重入锁解决的是重入锁定的问题,重入锁定(Reentrance Lockout)指的是当一个线程执行逻辑时,需要两次获取锁,而该锁不可重入就会导致内部嵌套无法获取锁导致Reentrance Lockout发生。Reentrance Lockout解决办法为一个线程两次获取锁的中间一定需要释放锁。
3.8.1 ReentrandLock继承关系
此处知道ReentrandLock是Lock接口的实现即可。
3.8.2 ReentradLock使用
声明锁即new创建锁。
static Lock lock = new ReentrantLock();
//修改时需要锁定的资源
static String text = "hello";
不加锁对text进行修改。
public static void modifyWithoutLock(){
text += " "+Thread.currentThread().getName();
}
public static void main(String[] args) throws InterruptedException {
modifyWithoutLock();
for (int i=0;i<100;i++) {
new Thread(() -> {
modifyWithoutLock();
}).start();
}
Thread.sleep(50);
System.err.println(text.length());
}
不加锁修改后text的长度为:
可知,对一个String变量多线程不加锁的情况下最后结果的长度很大概率是不一样的。
加锁对text进行修改。
public static void modify(){
//使用lock方法枷锁
lock.lock();
try {
text += " "+Thread.currentThread().getName();
}catch (Exception e){
e.printStackTrace();
}
finally {
//使用unlock方法解锁
lock.unlock();
}
}
加锁之后对多线程对text的修改最后的长度是一定的(这儿不能保证线程修改的顺序)。
3.8.2 ReentradLock方法介绍
ReentrandLock | 作用 |
---|---|
tryLock() | 尝试获取锁 |
tryLock(long timeout, TimeUnit unit) | 尝试获取锁,timeout是尝试获取锁的等待事件,超时不候,unit是等待时间的单位 |
unlock() | 释放锁 |
getHoldCount() | 当前线程持有该锁的次数 |
isHeldByCurrentThread() | 当前线程是否持有该锁 |
… | … |
3.8.3 ReentrandLock源码
构造方法
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
* 如果fair为true则构造是一个公平锁
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
ReentrandLock默认是非公平锁,也可以通过传入一个boolean fair的参数构造来声明该锁是公平锁还是非公平锁。
内部组成
private final Sync sync;
其内部由一个Sync sync属性组成,其是ReentradLock的内部类,Sync抽象内有NonfairSync和FairSync两种子类实现,分别表示非公平锁和公平锁。
加解锁方法
public void lock() {
sync.lock();
}
public void unlock() {
sync.release(1);
}
其具体实现其实是Sync的子类FairSync或者NonfairSync的方法,具体使用的哪个看构造的时候是公平锁还是非公平锁,对于Sync的解析放在后边再说。