为了保证数据安全使用 synchronized同步机制, 当线程进入堵塞状态 (不可运行状态和等待状态)时,其他线程无法访问那个加锁对象(除非同步锁被解除),所以 一个线程会一直处于等待另一个对象的状态, 而另一个对象又会处于等待下一个对象的状态,以此类推,这个线程“等待”状态链会发生很糟糕的情形,即封闭环状态(也就是说最后那个对象在等待第一个对象的锁)。此时,所有的线程都陷入毫无止境的等待状态中,无法继续运行, 这种情况就称为“死锁” 。虽然这种情况发生的概率很小,一旦出现,程序的调试变得困难而且查错也是一件很麻烦的事情。

    下面举一个死锁的例子。 

public class ThreadLocked implements Runnable {  
    public static boolean flag = true; // 起一个标志作用  
    private static Object A = new Object(); // 声明,并初始化静态Object数据域A  
  
    private static Object B = new Object(); // 声明,并初始化静态Object数据域B  
  
    public static void main(String[] args) throws InterruptedException {  
        Runnable r1 = new ThreadLocked(); // 创建,并初始化ThreadLocked对象r1  
        Thread t1 = new Thread(r1); // 创建线程t1  
        Runnable r2 = new ThreadLocked(); // 创建,并初始化ThreadLocked对象r2  
        Thread t2 = new Thread(r2); // 创建线程t2  
        t1.start(); // 启动线程t1  
        t2.start(); // 启动线程t2  
    }  
  
    public void AccessA() {  
        flag = false; // 初始化域flag  
        // 同步代码快  
        synchronized (A) { // 声明同步块,给对象A加锁  
            System.out.println("线程t1 : 我得到了A的锁"); // 输出字符串信息  
            try {  
                // 让当前线程睡眠,从而让另外一个线程可以先得到对象B的锁  
                Thread.sleep(1000); // 休眠  
            } catch (InterruptedException e) { // 捕获异常  
                e.printStackTrace(); // 异常信息输出  
            }  
            System.out.println("线程t1 : 我还想要得到B的锁");  
            // 在得到A锁之后,又想得到B的锁  
            // 同步块内部嵌套同步块  
            synchronized (B) { // 声明内部嵌套同步块,指定对象B的锁  
                System.out.println("线程t1 : 我得到了B的锁"); // 输出字符串信息  
            }  
        }  
    }  
  
    public void AccessB() {  
        flag = true; // 修改flag的值  
        // 同步代码块  
        synchronized (B) { // 指定同步块,给B加锁  
            System.out.println("线程t2 : 我得到了B的锁"); // 输出字符串信息  
            try {  
                // 让当前线程睡眠,从而让另外一个线程可以先得到对象A的锁  
                Thread.sleep(1000); // 休眠  
            } catch (InterruptedException e) { // 捕获异常InterruptedException  
                e.printStackTrace(); // 异常信息输出  
            }  
            System.out.println("线程t2 : 我还想要得到A的锁"); // 字符串信息输出  
            // 在得到B锁之后,又想得到A的锁  
            // 同步块内部嵌套内部快  
            synchronized (A) { // 指定同步块,给A加锁  
                System.out.println("线程t2 : 我得到了A的锁"); // 输出字符串信息  
            }  
        }  
    }  
  
    public void run() {  
        if (flag){ // 当flag为true,执行下面语句  
            AccessA(); // 调用AccessA方法  
        } else {  
            AccessB(); // 调用AccessB方法  
        }  
    }  
  
}


       程序 ThreadLocked.java中创建了两个线程 t1 和 t2,并且声明两个方法:AccessA和 AccessB。在运行过程中,线程t1 先获得了 A 的锁,然后又要求获得 B 的锁;而 t2 先获得B 的锁,然后又要求获得 A的锁,此时便进入了无休止的相互等待状态,即死锁。  Java 语言本身并没有提供防止死锁的具体方法,但是在具体程序设计时必须要谨慎,以防止出现死锁现象。通常在程序设计中应注意,不要使用 stop()、suspend()、resume()以及 destroy()方法。 stop()方法不安全,它会解除由该线程获得的所有对象锁,而且可能使对象处于不连贯状态,如果其他线程此时访问对象,而导致的错误很难检查出来。suspend()/resume ()方法也极不安全,调用 suspend()方法时,线程会停下来,但是该线程并没有放弃对象的锁,导致其他线程并不能获得对象锁。调用destroy()会强制终止线程,但是该线程也不会释放对象锁。