持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情
lockInterruptibly方法
代码示例
public class TestInterReen {
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
Thread t1 = new Thread(()->{
try {
System.out.println("t1尝试获取锁");
lock.lockInterruptibly();
} catch (InterruptedException e) {
System.out.println("t1被打断");
return;
}
try {
System.out.println("t1获取到锁");
}finally {
lock.unlock();
}
});
Thread t2 = new Thread(()->{
try {
System.out.println("t2尝试获取锁");
lock.lockInterruptibly();
} catch (InterruptedException e) {
System.out.println("t2被打断");
return;
}
try {
System.out.println("t2获取到锁");
Sleeper.sleep(2);
}finally {
}
});
t2.start();
Sleeper.sleep(0.5);
t1.start();
Sleeper.sleep(0.5);
System.out.println("打断正在等待锁的t1线程");
t1.interrupt();
}
}
结果:
程序结束:
t2尝试获取锁
t2获取到锁
t1尝试获取锁
打断正在等待锁的t1线程
t1被打断
解释:
可以看出我们用lockInterruptibly方法可以实现 打断处于阻塞状态的线程
锁超时
锁超时是指,一旦锁被其他线程占用 如果没有指定超时时间 则本线程会直接跳出阻塞状态 不参与竞争,如果指定了超时时间 则 超时时间内处于阻塞状态 超出超时时间 则跳出阻塞状态。
代码示例
@Slf4j(topic = "c.TestInterCS")
public class TestInterCS {
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
Thread t1 = new Thread(()->{
log.debug("t1尝试获取锁");
if (!lock.tryLock()){
log.debug("t1获取不到锁");
return;
}
try {
log.debug("t1获取到锁");
}finally {
}
},"t1");
Thread t2 = new Thread(()->{
log.debug("t2尝试获取锁");
if (!lock.tryLock()){
log.debug("t2获取不到锁");
return;
}
try {
log.debug("获取到锁");
}finally {
lock.unlock();
}
},"t2");
t1.start();
Sleeper.sleep(1);
t2.start();
}
}
结果:
- 00:40:27.595 c.TestInterCS [t1] - t1尝试获取锁
- 00:40:27.597 c.TestInterCS [t1] - t1获取到锁
- 00:40:28.600 c.TestInterCS [t2] - t2尝试获取锁
- 00:40:28.600 c.TestInterCS [t2] - t2获取不到锁
解释:
可以看出t1线程获取到锁并且没有释放,t2线程一直处于阻塞状态,我们用tryLock方法 且没有指定超时时间 也就是一旦发现t2线程处于阻塞状态lock.tryLock()返回false,我们执行其它代码
代码示例
@Slf4j(topic = "c.TestInterCS")
public class TestInterCS {
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
Thread t1 = new Thread(()->{
log.debug("t1尝试获取锁");
try {
if (!lock.tryLock(2, TimeUnit.SECONDS)){
log.debug("t1获取不到锁");
return;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
log.debug("t1获取到锁");
}finally {
}
},"t1");
Thread t2 = new Thread(()->{
log.debug("t2尝试获取锁");
if (!lock.tryLock()){
log.debug("t2获取不到锁");
return;
}
try {
log.debug("获取到锁");
}finally {
lock.unlock();
}
},"t2");
t1.start();
Sleeper.sleep(1);
t2.start();
}
}
结果:
- 00:44:46.180 c.TestInterCS [t1] - t1尝试获取锁
- 00:44:46.183 c.TestInterCS [t1] - t1获取到锁
- 00:44:47.183 c.TestInterCS [t2] - t2尝试获取锁
- 00:44:47.183 c.TestInterCS [t2] - t2获取不到锁
解释:
我们给tryLock方法指定时间为2s,但是因为t1线程始终没有释放锁,所以结果lock.tryLock()依然返回false,我们进行逻辑判断,执行其它的代码
条件变量
基本介绍
synchronized中也有条件变量,就是我们讲原理时Monitor中的WaitSet,当条件不满足时进入WaitSet中等待。 ReentrantLock的条件变量比synchronized强大之处在于 它是之处多个条件变量的 这就好比 synchronized是那些不满足条件的线程都在一间休息室等消息,而ReentrantLock支持多间休息室 有专门等烟条件的休息室 有专门等待早餐条件的休息室 唤醒时也是按照休息室来唤醒
使用流程
1.await前需要获取锁
2.await执行后 会释放锁 进入conditionObject等待
3.await的线程被唤醒(或打断 或超时)去重新竞争lock锁
4.竞争lock锁成功后 从await后继续执行
代码示例
@Slf4j(topic = "c.Test24")
public class Test24 {
static final Object room = new Object();
static boolean hasCigarette = false;
static boolean hasTakeout = false;
static ReentrantLock ROOM = new ReentrantLock();
// 等待烟的休息室
static Condition waitCigaretteSet = ROOM.newCondition();
// 等外卖的休息室
static Condition waitTakeoutSet = ROOM.newCondition();
public static void main(String[] args) {
new Thread(() -> {
ROOM.lock();
try {
log.debug("有烟没?[{}]", hasCigarette);
while (!hasCigarette) {
log.debug("没烟,先歇会!");
try {
waitCigaretteSet.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("可以开始干活了");
} finally {
ROOM.unlock();
}
}, "小南").start();
new Thread(() -> {
ROOM.lock();
try {
log.debug("外卖送到没?[{}]", hasTakeout);
while (!hasTakeout) {
log.debug("没外卖,先歇会!");
try {
waitTakeoutSet.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("可以开始干活了");
} finally {
ROOM.unlock();
}
}, "小女").start();
sleep(1);
new Thread(() -> {
ROOM.lock();
try {
hasTakeout = true;
waitTakeoutSet.signal();
} finally {
ROOM.unlock();
}
}, "送外卖的").start();
sleep(1);
new Thread(() -> {
ROOM.lock();
try {
hasCigarette = true;
waitCigaretteSet.signal();
} finally {
ROOM.unlock();
}
}, "送烟的").start();
}
}
结果:
01:20:49.292 c.Test24 [小南] - 有烟没?[false] 01:20:49.295 c.Test24 [小南] - 没烟,先歇会! 01:20:49.295 c.Test24 [小女] - 外卖送到没?[false] 01:20:49.295 c.Test24 [小女] - 没外卖,先歇会! 01:20:50.300 c.Test24 [小女] - 可以开始干活了 01:20:51.309 c.Test24 [小南] - 可以开始干活了
解释:
- 01:20:49.292 c.Test24 [小南] - 有烟没?[false]
- 01:20:49.295 c.Test24 [小南] - 没烟,先歇会!
- 01:20:49.295 c.Test24 [小女] - 外卖送到没?[false]
- 01:20:49.295 c.Test24 [小女] - 没外卖,先歇会!
- 01:20:50.300 c.Test24 [小女] - 可以开始干活了
- 01:20:51.309 c.Test24 [小南] - 可以开始干活了