版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cmm0401/article/details/82711660
多线程之死锁
1、锁对象Lock
虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁。
为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock。
- Lock:是一个接口
- void lock()
- void unlock()
- ReentrantLock:Lock接口的一个具体实现类
2、同步弊端:
- 效率低
- 如果出现了同步嵌套,就容易产生死锁问题
3、死锁问题及其代码演示:
- 是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待的现象
- 同步代码块的嵌套案例
(1)创建线程类
package cn.itcast_02;
public class DieLock extends Thread {
private boolean flag;
public DieLock(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if (flag) {
synchronized (MyLock.objA) {
System.out.println("if objA");
synchronized (MyLock.objB) {
System.out.println("if objB");
}
}
} else {
synchronized (MyLock.objB) {
System.out.println("else objB");
synchronized (MyLock.objA) {
System.out.println("else objA");
}
}
}
}
}
(2)创建锁
package cn.itcast_02;
public class MyLock {
// 创建两把锁对象
public static final Object objA = new Object();
public static final Object objB = new Object();
}
(3)测试线程类
package cn.itcast_02;
/*
* 同步的弊端:
* A:效率低
* B:容易产生死锁
* 死锁:
* 两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象。
* 举例:
* 中国人,美国人吃饭案例。
* 正常情况:
* 中国人:筷子两支
* 美国人:刀和叉
* 现在:
* 中国人:筷子1支,刀一把
* 美国人:筷子1支,叉一把
*/
public class DieLockDemo {
public static void main(String[] args) {
DieLock dl1 = new DieLock(true);
DieLock dl2 = new DieLock(false);
dl1.start();
dl2.start();
}
}
(4)两个线程使用各自的锁,出现了问题:
- 线程dl1使用锁A输出一句话“if objA”,然后被线程dl2抢去了CPU资源而被迫阻塞;
- 此时线程dl2使用锁B输出一句话“else objB”,然后又被线程dl1抢去了CPU资源而被迫阻塞;
- 这时,线程dl1想继续执行下一句话,但是需要锁B,而锁B这时候被线程dl2占用着,所以又被迫阻塞;
- 这时,如果线程dl2又抢到了CPU资源想继续向下执行的话,但是需要正在被线程dl1占用的锁A,所以又被迫阻塞;
- 依次产生死锁问题。