介绍
相对于synchronized,它具备如下特点
- 可重入
- 可中断
- 可设置超时时间
- 可设置公平锁
- 支持多个条件变量
与synchronized一样,都支持可重入。
基本语法:
ReentrantLock lock = new ReentrantLock();
//获取锁
lock.lock();
try {
//临界区
}finally {
//释放锁
lock.unlock();
}
可重入
可重入是指同一个线程如果首次获得了这把锁,那么它是这把锁的拥有者,因此有权利再次获取这把锁。
static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
method1();
}
public static void method1(){
lock.lock();
try {
System.out.println("method1");
method2();
}finally {
lock.unlock();
}
}
private static void method2() {
lock.lock();
try {
System.out.println("method2");
}finally {
lock.unlock();
}
}
如果不可重入,则在执行method2方法的时候就会被挡住,而method1和method2都成功执行,所以ReentrantLock具有可重入特性。
可打断
ReentrantLock.lockInterruptibly()方法:如果没有竞争,那么此方法就会获取lock锁,如果有竞争就会进入阻塞队列,可以被其他线程用interrupt打断。
static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
try {
System.out.println("尝试获取锁");
lock.lockInterruptibly();
} catch (InterruptedException e) {
System.out.println("获取锁失败,返回");
return;
}
try {
System.out.println("获取到锁");
} finally {
lock.unlock();
}
}, "t1");
lock.lock();
t1.start();
TimeUnit.SECONDS.sleep(2);
System.out.println("打断t1");
t1.interrupt();
}
锁超时
tryLock方法:一个有参,一个无参
static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
System.out.println("尝试获取锁");
try {
if(!lock.tryLock(5, TimeUnit.SECONDS)){
System.out.println("获取锁失败,返回");
return;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
System.out.println("获取到锁");
} finally {
lock.unlock();
}
}, "t1");
lock.lock();
t1.start();
TimeUnit.SECONDS.sleep(3);
System.out.println("主线程释放锁");
lock.unlock();
}
公平锁
ReentrantLock默认是不公平的。
可以通过它的构造方法设置公平性
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
条件变量
使用流程:
- await前需要获得锁
- await执行后,会释放锁,进入Condition中等待
- await的线程被唤醒(或打断或超时)去重新竞争lock锁
- 竞争lock锁成功后,从await后继续执行
private static final Lock lock = new ReentrantLock();
private static final Condition condition = lock.newCondition();
public static void main(String[] args) {
new Thread(()->{
try {
lock.lock();
System.out.println("在等一个信号"+Thread.currentThread().getName());
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
System.out.println("拿到一个信号"+Thread.currentThread().getName());
lock.unlock();
}
}).start();
new Thread(()->{
try {
lock.lock();
System.out.println("拿到锁"+Thread.currentThread().getName());
condition.signalAll();
System.out.println("发出了一个信号:"+Thread.currentThread().getName());
} finally{
lock.unlock();
}
}).start();
}