Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Latest commit

 

History

History
History
124 lines (95 loc) · 6 KB

File metadata and controls

124 lines (95 loc) · 6 KB
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
java级别死锁
## 什么是死锁
死锁不仅在个人学习中甚至在开发中也并不常见但是一旦出现死锁后果将非常严重
首先什么是死锁呢打个比方就好像有两个人打架互相限制住了(锁住抱住)彼此一样互相动弹不得而且互相欧气你不松手我就不松手好了谁也动弹不得
在多线程的环境下势必会对资源进行抢夺当两个线程锁住了当前资源但都需要对方的资源才能进行下一步操作这个时候两方就会一直等待对方的资源释放这就形成了死锁这些永远在互相等待的进程称为死锁进程
那么我们来总结一下死锁产生的条件
1. 互斥:资源的锁是排他性的加锁期间只能有一个线程拥有该资源其他线程只能等待锁释放才能尝试获取该资源
2. 请求和保持:当前线程已经拥有至少一个资源但其同时又发出新的资源请求而被请求的资源被其他线程拥有此时进入保持当前资源并等待下个资源的状态
3. 不剥夺线程已拥有的资源只能由自己释放不能被其他线程剥夺
4. 循环等待是指有多个线程互相的请求对方的资源但同时拥有对方下一步所需的资源形成一种循环类似2)请求和保持但此处指多个线程的关系并不是指单个线程一直在循环中等待
什么还是不理解那我们直接上代码动手写一个死锁
## 动手写死锁
根据条件我们让两个线程互相请求保持
```java
public class DeadLockDemo implements Runnable{
public static int flag = 1;
//static 变量是 类对象共享的
static Object o1 = new Object();
static Object o2 = new Object();
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":此时 flag = " + flag);
if(flag == 1){
synchronized (o1){
try {
System.out.println("我是" + Thread.currentThread().getName() + "锁住 o1");
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName() + "醒来->准备获取 o2");
}catch (Exception e){
e.printStackTrace();
}
synchronized (o2){
System.out.println(Thread.currentThread().getName() + "拿到 o2");//第24行
}
}
}
if(flag == 0){
synchronized (o2){
try {
System.out.println("我是" + Thread.currentThread().getName() + "锁住 o2");
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName() + "醒来->准备获取 o2");
}catch (Exception e){
e.printStackTrace();
}
synchronized (o1){
System.out.println(Thread.currentThread().getName() + "拿到 o1");//第38行
}
}
}
}
public static void main(String args[]){
DeadLockDemo t1 = new DeadLockDemo();
DeadLockDemo t2 = new DeadLockDemo();
t1.flag = 1;
new Thread(t1).start();
//让main线程休眠1秒钟,保证t2开启锁住o2.进入死锁
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.flag = 0;
new Thread(t2).start();
}
}
```
代码中
t1创建t1先拿到o1的锁开始休眠3秒然后
t2线程创建t2拿到o2的锁开始休眠3秒然后
t1先醒来准备拿o2的锁发现o2已经加锁只能等待o2的锁释放
t2后醒来准备拿o1的锁发现o1已经加锁只能等待o1的锁释放
t1,t2形成死锁
我们查看运行状态
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190329173537340.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3RpbW8xMTYwMTM5MjEx,size_16,color_FFFFFF,t_70)
## 发现排查死锁情况
我们利用jdk提供的工具定位死锁问题
1. jps显示所有当前Java虚拟机进程名及pid.
2. jstack打印进程堆栈信息
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190329174354777.png)
列出所有java进程
我们检查一下DeadLockDemo为什么这个线程不退栈
```shell
jstack 11170
```
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190329174417873.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3RpbW8xMTYwMTM5MjEx,size_16,color_FFFFFF,t_70)
我们直接翻到最后:已经检测出了一个java级别死锁其中两个线程分别卡在了代码第38行和第24行检查我们代码的对应位置即可排查错误此处我们是第二个锁始终拿不到所以死锁了
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190329174407208.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3RpbW8xMTYwMTM5MjEx,size_16,color_FFFFFF,t_70)
## 解决办法
死锁一旦发生我们就无法解决了所以我们只能避免死锁的发生
既然死锁需要满足四种条件那我们就从条件下手只要打破任意规则即可
1.互斥尽量少用互斥锁能加读锁不加写锁当然这条无法避免
2.请求和保持采用资源静态分配策略进程资源静态分配方式是指一个进程在建立时就分配了它需要的全部资源).我们尽量不让线程同时去请求多个锁或者在拥有一个锁又请求不到下个锁时不保持等待先释放资源等待一段时间在重新请求
3.不剥夺允许进程剥夺使用其他进程占有的资源优先级
4.循环等待尽量调整获得锁的顺序不发生嵌套资源请求加入超时
Morty Proxy This is a proxified and sanitized view of the page, visit original site.