死锁:当一个线程永远地持有一个锁,并且其他线程都尝试获得这个锁时,那么它们将永远被阻塞。比如,线程1已经持有了A锁并想要获得B锁的同时,线程2持有B锁并尝试获取A锁,那么这两个线程将永远地等待下去。
我们来看一个死锁的简单例子:
1 public class DeadLockTest
2 {
3 private static Object A = new Object(), B = new Object();
4
5 public static void main(String[] args)
6 {
7 new Thread(() -> {
8 System.out.println("线程1开始执行...");
9 synchronized (A)
10 {
11 try
12 {
13 System.out.println("线程1拿到A锁");
14 //休眠两秒让线程2有时间拿到B锁
15 Thread.sleep(2000);
16 } catch (Exception e)
17 {
18 e.printStackTrace();
19 }
20 synchronized (B)
21 {
22 System.out.println("线程1拿到B锁");
23 }
24 }
25 }).start();
26
27 new Thread(() -> {
28 System.out.println("线程2开始执行...");
29 synchronized (B)
30 {
31 try
32 {
33 System.out.println("线程2拿到B锁");
34 //休眠两秒让线程1有时间拿到A锁
35 Thread.sleep(2000);
36 } catch (Exception e)
37 {
38 e.printStackTrace();
39 }
40 synchronized (A)
41 {
42 System.out.println("线程2拿到A锁");
43 }
44 }
45 }).start();
46
47 }
48 }
运行结果:
从运行结果可看到,线程1拿到了A锁,并尝试去获取B锁,与此同时线程2拿到了B锁并尝试去获取A锁,此时线程1和线程2就陷入了无限的等待,形成死锁。
那么要怎么预防死锁呢?下面介绍几个常见方法:
1、避免一个线程同时获取多个锁
2、避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
3、尝试使用定时锁,使用lock.tryLock来代替使用内置锁。
详情可参考《Java并发编程实战》