【面试:并发篇20:多线程:多把锁问题】
00.前言
如果有任何问题请指出,感谢。
01.介绍
我们现在有这么一个问题,有一个房子 有卧室和书房,书房可以用来学习 卧室可以用来睡觉,但是学习和睡觉两件事不冲突,不过学习和学习直接冲突 睡觉和睡觉冲突。这个就是我们的问题,如果仅仅只有房子这一把锁,势必会导致 睡觉的时候 房子被占用 不能用来学习,显然是不合适的。
02.案例
public class TestMultiLock {
public static void main(String[] args) {
BigRoom bigRoom = new BigRoom();
new Thread(() -> {
bigRoom.study();
},"小南").start();
new Thread(() -> {
bigRoom.sleep();
},"小女").start();
}
}
@Slf4j(topic = "c.BigRoom")
class BigRoom {
public void sleep() {
synchronized (this) {
log.debug("sleeping 2 小时");
Sleeper.sleep(2);
}
}
public void study() {
synchronized (this) {
log.debug("study 1 小时");
Sleeper.sleep(1);
}
}
}
结果
00:23:51.597 c.BigRoom [小南] - study 1 小时
00:23:52.607 c.BigRoom [小女] - sleeping 2 小时
解释
可以看出小南与小女都想使用这个屋子,但是小南先抢到 学习了1h后小南才开始睡2h,但是就如我们题目描述 睡觉与学习没有关系 理论上 他俩应该同时开始。
03.解决方案
public class TestMultiLock {
public static void main(String[] args) {
BigRoom bigRoom = new BigRoom();
new Thread(() -> {
bigRoom.study();
},"小南").start();
new Thread(() -> {
bigRoom.sleep();
},"小女").start();
}
}
@Slf4j(topic = "c.BigRoom")
class BigRoom {
private final Object studyRoom = new Object();
private final Object bedRoom = new Object();
public void sleep() {
synchronized (bedRoom) {
log.debug("sleeping 2 小时");
Sleeper.sleep(2);
}
}
public void study() {
synchronized (studyRoom) {
log.debug("study 1 小时");
Sleeper.sleep(1);
}
}
}
结果
00:27:56.494 c.BigRoom [小南] - study 1 小时
00:27:56.494 c.BigRoom [小女] - sleeping 2 小时
解释
我们在BigRoom类中又创建了两个 对象 分别是studyRoom、bedRoom作为学习与睡觉的锁,这就是用多把锁来解决这个问题。
04.多把锁的优缺点
优点
优点很明显,细分了锁的粒度 可以增强并发度
缺点
缺点是,如果一个线程需要同时获得多把锁,那就容易发生死锁