相对于synchronized 具备以下特点:
- 可重入(synchronized也可重入)
- 由其方法控制锁的开启和释放
- 线程等待可中断(lock.lockInterruptibly():拿不到锁就跳过,不进入阻塞态)
- 可设置超时时间(lock.tryLock():拿不到锁返回false,也不会进入阻塞态)
- 可设置为公平锁
- 支持多个条件变量(con1.await();con1.singal();con1.singalAll(),可以精准)
语法:
reentrantLock.lock()
try {
//临界区
} finally {
//释放锁
reentrantLock.unlock();
}
可重入:
是指同一个线程如果哦首次获得了这把锁,那么以为他是这把锁的拥有者,因此有权利再次获得这把锁。synchronized 和 reentrantLock 均可重入
线程等待可打断:
如果别的线程持有锁资源,当前线程会一直等待,无法被充分利用,因此要加上可打断的功能
【注:】上锁时要用 lock.lockInterruptibly(),因为lock.lock() 不支持打断
public class Test{
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args){
Thread t1 = new Thread(()->{
try{
//如果此时该锁未被占用,就会获取该锁
//如果此时该锁被占用,就会进入阻塞队列,不会一直等待
System.out.println("尝试获得锁");
lock.lockInterruptibly();
System.out.println("已经获得锁");
}
catch (InterruptedException e){
e.printStackTrace()
}
},"t1");
t1.start();
}
}
返回结果:
尝试获得锁
已经获得锁
-------------------------
t1线程获得锁,正常结束
public class Test{
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args){
Thread t1 = new Thread(()->{
try{
//如果此时该锁未被占用,就会获取该锁
//如果此时该锁被占用,就会进入阻塞队列,不会一直等待
System.out.println("尝试获得锁");
lock.lockInterruptibly();
}
catch (InterruptedException e){
e.printStackTrace()
System.out.println("无法获得锁");
return ;
}
},"t1");
//主线程先获得锁
lock.lock()
//再开t1线程
t1.start();
}
}
返回结果:
尝试获得锁
-------------------------
t1线程未打断,一直等待
public class Test{
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args){
Thread t1 = new Thread(()->{
try{
//如果此时该锁未被占用,就会获取该锁
//如果此时该锁被占用,就会进入阻塞队列,不会一直等待
System.out.println("尝试获得锁");
lock.lockInterruptibly();
}
catch (InterruptedException e){
e.printStackTrace()
System.out.println("无法获得锁");
return ;
}
},"t1");
//主线程先获得锁
lock.lock()
//再开t1线程
t1.start();
//睡眠后打断
sleep(2);
t1.interrupt();
}
}
返回结果:
尝试获得锁
无法获得锁
-------------------------
先尝试获得锁,2s后,主线程对t1线程执行了interrupt(),t1打断标记置为true,一直等待的t1线程被打断,在异常处理时将其结束
【注:】再次提醒 synchronized 和 lock.lock() 的等待无法打断
【Java并发】synchronized不可以被中断?_runhua的博客-CSDN博客_synchronized可以被中断吗
锁超时:
lock.tryLock() 如果获得锁返回 true,如果没有拿到锁立刻返回false
lock.tryLock(time) 如果获得锁返回 true,如果等待时间内活得锁返回 true,如果超时还在等待返回 false
优点:
可以化解线程因拿不到锁而陷入死锁的问题——哲学家就餐问题
可设置为公平锁:
ReentrantLock 默认构造器创建的是非公平锁机制,可以通过 new ReentrantLock(true) 创建公平锁,但是公平锁一般不会用到,因为公平锁会降低并发性能
条件变量:
条件变量就是Monitor里的waitSet变量,执行了wait() 的线程会进入该变量等待,这个变量就是条件变量
相较于synchronized,reentrantLock 拥有了创建Monitor的能力,因此一个reentrantLock对象可以创建多个Monitor对象,实现语法:
Condition con1 = reentrantLock.newCondition()
Condition con2 = reentrantLock.newCondition()
如此一个reentrantLock对象可以管理多个Monitor,也就是可以管理多个条件变量,灵活了等待、唤醒机制
等待:
con1.await()
con2.await()
唤醒:
con1.singal() 、con1.singalAll()