死锁:当一个线程永远地持有一个锁,并且其他线程都尝试获得这个锁时,那么它们将永远被阻塞。比如,线程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并发编程实战》