原文 http://blog.sina.com.cn/s/blog_6b7bda7f0100m0wl.html
当两个或多个线程之间同时等待对方释放资源的时候就会形成线程之间的死锁当两个线程被阻塞,每个线程在等待另一个线程时就发生死锁 当多个线程等待一个对象锁时,没有获取到锁的线程将发生阻塞。 线程的阻塞 : 1. sleep() 方法:sleep()允许指定以毫秒为单位的一段时间作为参数,它使得线程在指定的时间内进入阻塞状态,不能得到CPU时间,指定的时间一过,线程重新进入可执行状态。 线程不会释放它的“锁标志”. 2. suspend() 和 resume()方法:两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的resume()被调用,才能使得线程重新进入可执行状态。典型地,suspend() 和 resume()被用在等待另一个线程产生的结果的情形:测试发现结果还没有产生后,让线程阻塞,另一个线程产生了结果后,调用 resume()使其恢复。 3. yield() 方法:yield() 使得线程放弃当前分得的 CPU时间,但是不使线程阻塞,即线程仍处于可执行状态,随时可能再次分得 CPU 时间。调用 yield()的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程。 4. wait() 和 notify() 方法:两个方法配套使用,wait()使得线程进入阻塞状态,它有两种形式,一种允许指定以毫秒为单位的一段时间作为参数,另一种没有参数,并且该对象上的锁被释放.前者当对应的notify() 被调用或者超出指定时间时线程重新进入可执行状态,后者则必须对应的 notify() 被调用 public class DeadLock { public static void main(String[] args) { Object o1 = new Object(); // 资源1 Object o2 = new Object(); // 资源2 Runner r1 = new Runner(1, o1, o2, 5000); // 线程1 Runner r2 = new Runner(2, o2, o1, 500); // 线程2 new Thread(r1).start(); new Thread(r2).start(); } } class Runner implements Runnable { private int id; private Object o1; // 所需的资源1 private Object o2; // 所需的资源2 private int sleep; public Runner(int id, Object o1, Object o2, int sleep) { this.id = id; this.o1 = o1; this.o2 = o2; this.sleep = sleep; } public void run() { System.out.println(id); // 锁定资源1 synchronized (o1) { try { Thread.sleep(sleep); // 这里主要是放大效果,让其他线程获取到时间片 } catch (InterruptedException e) { e.printStackTrace(); } // 锁定资源2 synchronized (o2) { System.out.println("Runner " + id); } } } } sleep:它使得线程在指定的时间内进入阻塞状态,不能得到CPU时间,把执行机会给其他线程,但是监控状态依然保持,不会 释放对象锁的.
导致死锁的根源在于不适当地运用“synchronized”关键词来管理线程对特定对象的访问。“synchronized”关键词的作用是,确保在某个时刻只有一个线程被允许执行特定的代码块,因此,被允许执行的线程首先必须拥有对变量或对象的排他性访问权。当线程访问对象时,线程会给对象加锁,而这个锁导致其它也想访问同一对象的线程被阻塞,直至第一个线程释放它加在对象上的锁。 一般造成死锁必须同时满足如下4个条件: 互斥条件 线程使用的资源必须至少有一个是不能共享的。 请求与保持条件 至少有一个线程必须持有一个资源并且正在等待获取一个当前被其他线程持有的资源。 非剥夺条件 分配的资源不能从相应的线程中被强制剥夺。 循环等待条件 第一个线程等待其他线程,后者又在等待第一个线程。 因为要发生死锁,这4个条件必须同时满足,所以要防止死锁的话,只需要破坏其中一个条件即