并发线程之间的死锁通常发生在同步代码块的相互嵌套使用的过程中,下面先来看段代码:
package cn.sunzn.synchronize; public class DeadLock { public static void main(String[] args) { final Object lock1 = new Object(); final Object lock2 = new Object(); /** 线程 0 **/ new Thread() { public void run() { synchronized (lock1) { System.out.println(Thread.currentThread().getName() + ":1"); synchronized (lock2) { System.out.println(Thread.currentThread().getName() + ":2"); } } }; }.start(); /** 线程 1 **/ new Thread() { public void run() { synchronized (lock2) { System.out.println(Thread.currentThread().getName() + ":3"); synchronized (lock1) { System.out.println(Thread.currentThread().getName() + ":4"); } } }; }.start(); } }
以上的代码在程序运行过程中开启了 2 个并发线程,线程 0 和线程 1 中同时嵌套使用同步代码块,大多数情况下程序能依次在屏幕上输出:
Thread-0:1 Thread-0:2 Thread-1:3 Thread-1:4
对于以上容易理解的运行结果不进行解释,下面看另一种运行结果:
Thread-0:1
Thread-1:3
下面我们对这个运行结果进行分析:首先前提条件线程 0 和线程 1 同时开启,CPU 切换到线程 0,打印输出 Thread-0:1,这时 CPU 切换到 线程 1 打印输出 Thread-1:3, 当线程 1 继续执行内部的同步代码块的时候发现内部的同步代码块和线程 0 的外部同步代码块使用了相同的锁对象 lock1,所以线程 1 会等待 CPU 切换到线程 0 等待与之同步的代码执行完毕,当线程 0 重新获取到 CPU 资源继续执行自身内部的同步代码块的时候发现线程 1 中的外部同步代码块和它具有同样的锁对象 lock2,所以线程 0 就会等待 CPU 切换到线程 1 等待与之同步的代码执行完毕,而这时线程 1 也在等待线程 0 的执行完毕,2 组代码相互等待,出现死锁。