通过jvsualvm也可以观察(也是在jdk的bin目录下):
一、死锁示例
代码演示:
package thread.threaddemo;
import java.util.concurrent.TimeUnit;
/**
* @Author: wenjingyuan
* @Date: 2022/11/20/11:05
* @Description:死锁示例
*/
public class ThreadDemo18 {
public static void main(String[] args) {
Object lockA=new Object();
Object lockB=new Object();
Thread t1=new Thread(()->{
synchronized (lockA){
System.out.println("线程1获得了A");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB){
System.out.println("线程1或得到B");
}
}
});
t1.start();
Thread t2=new Thread(()->{
synchronized (lockB){
System.out.println("线程2获得了B");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockA){
System.out.println("线程2或得到A");
}
}
});
t2.start();
}
}
执行结果:
我们通过jconsole工具再来看一次
通过jvsualvm也可以观察(也是在jdk的bin目录下):
还可以通过jmc来观察:
这里我们将不做详细的叙述!
总结:
两个线程在拥有锁的情况下,在尝试获取对方的锁,从而导致程序进入阻塞状态
二、死锁产生原因
1.互斥问题
一个资源只能被一个线程占有,当这个资源被占用以后其他的线程只能等待
2.不可被剥夺条件
当一个线程占用一个资源的时候,如果不主动释放资源这个资源就只能被一直占用
3.请求并持有条件
当线程拥有某个资源的时候,还不满足,又在请求其他的资源
4.环路等待条件
多个线程在请求资源的时候形成环路链
注意:发生死锁并不是说这四个其中一个的因素,是四个因素共同导致了死锁!(缺一不可)
三、如何解决死锁?
思路:打破形成死锁的一个或者多个条件即可!
首先我们分析可知,条件中的三四是人为可以修改的。
1.我们先进行改变条件三,请求并持有条件。
代码如下:
package thread.threaddemo;
import java.util.concurrent.TimeUnit;
/**
* @Author: wenjingyuan
* @Date: 2023/01/14/19:04
* @Description:解决死锁,破坏请求并持有条件
*/
public class UnDeadLock {
public static void main(String[] args) {
Object lockA=new Object();
Object lockB=new Object();
Thread t1=new Thread(()->{
synchronized (lockA){
System.out.println("线程1拿到了锁A");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
// synchronized (lockB){
// System.out.println("线程1拿到了锁B");
// //业务代码
// System.out.println("线程1释放了锁B");
// }
System.out.println("线程1释放了锁A");
}
},"线程1");
t1.start();
Thread t2=new Thread(()->{
synchronized (lockB){
System.out.println("线程2拿到了锁B");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
// synchronized (lockA){
// System.out.println("线程2拿到了锁A");
// //业务代码
// System.out.println("线程2释放了锁A");
// }
System.out.println("线程2释放了锁B");
}
},"线程2");
t2.start();
}
}
运行结果如下:
2.接下来我们改变条件四,改变环路条件(也叫做使用顺序锁解决死锁问题),代码如下:
package thread.threaddemo;
import java.util.concurrent.TimeUnit;
/**
* @Author: wenjingyuan
* @Date: 2023/01/14/19:04
* @Description:解决死锁,破坏环路等待条件
*/
public class UnDeadLock2 {
public static void main(String[] args) {
Object lockA=new Object();
Object lockB=new Object();
Thread t1=new Thread(()->{
synchronized (lockA){
System.out.println("线程1拿到了锁A");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB){
System.out.println("线程1拿到了锁B");
//业务代码
System.out.println("线程1释放了锁B");
}
System.out.println("线程1释放了锁A");
}
},"线程1");
t1.start();
Thread t2=new Thread(()->{
synchronized (lockA){
System.out.println("线程2拿到了锁A");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB){
System.out.println("线程2拿到了锁B");
//业务代码
System.out.println("线程2释放了锁B");
}
System.out.println("线程2释放了锁A");
}
},"线程2");
t2.start();
}
}
运行结果如下: