死锁的必要条件
-
互斥条件
-
请求和保持条件
-
不剥夺条件
-
环路等待条件
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 1/**
2 * 一个简单的死锁类
3 * 当DeadLock的对象flag==1时(d1), 先锁定o1,睡眠500毫秒
4 * 而d1在睡眠的时候留一个flag=0的对象(d2)线程启动,先锁定o2,睡眠500毫秒
5 * d1睡眠结束后需要锁定o2才能继续执行,而此时o2已经被d2锁定;
6 * d2睡眠结束后需要锁定o1才能继续执行,而此时o1已经被d1锁定;
7 * d1,d2相互等待,都需要得到对方锁定改的资源才能继续执行,从而死锁
8 */
9@Slf4j
10public class DeadLock implements Runnable {
11
12 public int flag = 1;
13 //静态资源是类的所有对象共享的
14 private static Object o1 = new Object(), o2 = new Object();
15
16 @Override
17 public void run() {
18 log.info("flag:{}", flag);
19 if(flag == 1){
20 synchronized (o1) {
21 try{
22 Thread.sleep(500);
23 } catch (Exception e){
24 e.printStackTrace();
25 }
26 synchronized (o2) {
27 log.info("1");
28 }
29 }
30 }
31 if (flag == 0) {
32 synchronized (o2) {
33 try {
34 Thread.sleep(500);
35 }catch (Exception e){
36 e.printStackTrace();
37 }
38 synchronized (o1) {
39 log.info("0");
40 }
41 }
42 }
43 }
44
45 public static void main(String[] args) {
46 DeadLock d1 = new DeadLock();
47 DeadLock d2 = new DeadLock();
48 d1.flag = 1;
49 d2.flag = 0;
50 //d1,d2都处于可执行状态,但JVM线程调度先执行哪个线程是不确定的。
51 //d2的run()可能在d1的run()之前执行
52 new Thread(d1).start();
53 new Thread(d2).start();
54 }
55}
56
如何避免死锁:
- 注意加锁顺序
- 加锁时间限制,可以使用ReentrantLock可以设置获取所得给定时间,超过一定时间就释放自己占用的锁
spring与线程安全
spring bean:提供了一个scope属性来表示该bean的作用域,是bean的生命周期。例如scope=singleton,表示单例,在第一次注入时会产生一个单例对象,该对象会一直复用到应用结束,这时默认的scope;
scope=prototype,表示在每次注入时都会创建一个bean对象