Reentrant Lock
相比synchronized,它具备以下特点:
- 可中断
- 可以设置超时时间
- 可以设置为公平锁
- 支持多个条件变量:进入不同的waitSet
与synchronized一样,支持可重入
基本语法
reentrantLock.lock()
try{
//临界区
}finally {
//释放锁
reentrantLock.unlock();
}
可重入
可重入是指同一个线程如果首次获得了这把锁,因为它是这把锁的拥有者,因此有权利再次获取这把锁。
如果是不可重入,那么第二次获得锁时,自己也会被锁挡住。
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.ReentrantLock;
@Slf4j(topic = "reentrantLockTest")
public class ReentrantLockTest {
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
lock.lock();
try {
System.out.println("进入main");
m1();
}finally {
lock.unlock();
}
}
public static void m1() {
lock.lock();
try {
System.out.println("进入m1");
m2();
}finally {
lock.unlock();
}
}
public static void m2() {
lock.lock();
try {
System.out.println("进入m2");
}finally {
lock.unlock();
}
}
}

结果说明reentrantLock可重入
可打断
使用reentrantLock.lockInterruptibly();,尝试获取一个可以被打断的锁
使用reentrantLock.lock();,尝试获取一个不可被打断的锁
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.ReentrantLock;
@Slf4j(topic = "testInterruptibly")
public class ReentrantLockTestInterruptibly {
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
try {
log.debug("尝试获取一个可打断的锁");
lock.lockInterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
log.debug("没有获得到锁,直接返回");
return;
}
log.debug("获取到锁");
lock.unlock();
},"t1");
//主线程加锁
lock.lock();
t1.start();
Thread.sleep(2000);
t1.interrupt();
}
}

改为lock.lock();,则t1.interrupt();不能打断。
锁超时
立即失败
lock.tryLock()尝试获得锁。如果成功,则返回true获得锁,如果失败,则返回false,不等待。
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.ReentrantLock;
@Slf4j
public class ReentrantLockTestTimeout {
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread( () -> {
log.debug("尝试获得锁..");
if ( !lock.tryLock()){
log.debug("未获得锁.");
return;
}
try {
log.debug("获得到锁,执行临界区代码");
} finally {
lock.unlock();
}
},"t1");
lock.lock();
t1.start();
}
}

超时失败
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
@Slf4j
public class ReentrantLockTestTimeout {
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread( () -> {
log.debug("尝试获得锁..");
try {
if ( !lock.tryLock(2, TimeUnit.SECONDS)){
log.debug("超时未获得锁.");
return;
}
} catch (InterruptedException e) {
e.printStackTrace();
log.debug("被打断,未获得锁");
return;
}
try {
log.debug("获得到锁,执行临界区代码");
} finally {
lock.unlock();
}
},"t1");
lock.lock();
t1.start();
Thread.sleep(3000);
// t1.interrupt();
lock.unlock();
}
}

公平锁
ReentrantLock默认是不公平锁
ReentrantLock lock = new ReentrantLock(true);改为公平锁。
公平锁一般没必要设置,会降低并发度。公平锁主要用于解决饥饿问题。
条件变量
synchronized中也有条件变量。当条件不满足时进入waitSet等待。
ReentrantLock的条件变量比synchronized的强大之处在于,ReentrantLock支持多个条件变量,有多个等待队列。
使用流程:
- await前需要获得锁
- await执行后会释放锁,进入conditionObject等待
- await的线程被唤醒(打断/超时),重新竞争lock锁
- 竞争lock锁成功后,从await后继续执行
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@Slf4j(topic = "testCondition")
public class ReentrantLockTestCondition {
static ReentrantLock ROOM = new ReentrantLock();
static Condition waitSet1 = ROOM.newCondition();
static Condition waitSet2 = ROOM.newCondition();
static boolean flag1 = false;
static boolean flag2 = false;
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
ROOM.lock();
try {
while (!flag1){
try {
log.debug("条件不满足,继续等待..");
waitSet1.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("条件满足,执行临界区代码");
} finally {
ROOM.unlock();
}
},"t1").start();
new Thread(()->{
ROOM.lock();
try {
while (!flag2){
try {
log.debug("条件不满足,继续等待..");
waitSet2.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("条件满足,执行临界区代码");
} finally {
ROOM.unlock();
}
},"t2").start();
Thread.sleep(2000);
new Thread(()->{
ROOM.lock();
try {
log.debug("flag1置为true");
flag1 = true;
waitSet1.signal();
} finally {
ROOM.unlock();
}
},"c1").start();
new Thread(()->{
ROOM.lock();
try {
log.debug("flag2置为true");
flag2 = true;
waitSet2.signal();
} finally {
ROOM.unlock();
}
},"c2").start();
}
}

浙公网安备 33010602011771号