死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。
导致死锁的根源在于不适当地运用“synchronized”关键词来管理线程对特定对象的访问。“synchronized”关键词的作用是,确保在某个时刻只有一个线程被允许执行特定的代码块,因此,被允许执行的线程首先必须拥有对变量或对象的排他性的访问权。当线程访问对象时,线程会给对象加锁,而这个锁导致其它也想访问同一对象的线程被阻塞,直至第一个线程释放它加在对象上的锁。
由于这个原因,在使用“synchronized”关键词时,很容易出现两个线程互相等待对方做出某个动作的情形。代码一是一个导致死锁的简单例子。
package com.thread; public class TestThread13 { public static void main(String[] args) { DeadLock t1 = new DeadLock(); DeadLock t2 = new DeadLock(); t1.flag = 1; t2.flag = 0; new Thread(t1).start(); new Thread(t2).start(); } } class DeadLock implements Runnable{ public int flag = 1 ; static Object o1 = new Object(), o2 = new Object(); public void run() { System.out.println("flag :"+flag); if (flag == 1) { synchronized (o1) { System.out.println(Thread.currentThread().getName()+" o1 locked"); try{Thread.sleep(500);}catch(Exception e){e.printStackTrace();} synchronized (o2) { System.out.println(Thread.currentThread().getName()+" o2 locked"); System.out.println("1"); } } } if (flag == 0) { synchronized (o2) { System.out.println(Thread.currentThread().getName()+" o2 locked"); try{Thread.sleep(500);}catch(Exception e){e.printStackTrace();} synchronized (o1) { System.out.println(Thread.currentThread().getName()+" o1 locked"); System.out.println("0"); } } } } }
运行结果:
分析:t1线程启动了,但并没有打印“1”;t2线程启动了,但并没有打印"0".因为2个线程启动后都阻塞了。
说明: t1线程启动后,占领监视器o1后,休眠500毫秒,这时t2线程占领了监视器o2,从此以后程序就堵塞了。正如截图结果。
原因是,t1线程占有监视器o1,等待t2线程释放监视器o2;同时,t2线程占有监视器o2,等待t1线程释放监视器o1, t1和t2这两个线程都在等对方先释放监视器,结果谁都不先释放,所以2个线程会一直堵塞。t1线程不能继续执行打印"1", t2线程不能继续执行打印“0”。