Java并发与多线程(1) 死锁是什么

节选自《Java完全参考手册》(第8版)


需要避免的与多任务明确相关的特殊类型的错误是死锁——deadlock,当两个线程循环依赖一对同步对象时,会发生这种情况。例如,假设一个线程进入对象Y的监视器。如果X中的线程试图调用对象Y的任何同步方法,则会被堵塞。但是,如果对象Y中的线程也试图调用A的任何同步方法,那么会永远等待下去,因为为了进入X,必须释放对Y加的锁,这样第一个线程才能完成。死锁是一种很难调试的错误,原因有二:

 

1.死锁通常很少发生,只有当两个线程恰好以这种方式获取CPU时钟周期时才会发生死锁

2.死锁可能涉及更多的线程以及更多的同步对象(也即是说,死锁可能是通过更加复杂的事件序列发生的


下面的例子创建了两个类——A 和B,他们分别有方法foo(),bar(), 在调用其他类中的方法之前会暂停一会儿。主类Deadlock分别创建一个A和B的实例,然后开始第二个线程以设置死锁条件。方法foo()和barI()使用sleep()作为强制死锁条件发生的手段。


// A example of deadlock
class A {
	
	synchronized void foo( B b ){
		String name = Thread.currentThread().getName();
		
		System.out.println(name + " enter A.foo");
		
		try{
			Thread.sleep(1000);
		} catch ( Exception e ) {
			System.out.println("A interrupted");
		}
		
		System.out.println( name + " trying to call B.last()");
		b.last();
	}
	
	synchronized void last() {
		System.out.println("Inside A.last");
	}
	
}

class B {
	
	synchronized void bar( A a ) {
		String name = Thread.currentThread().getName();
		
		System.out.println(name + " entered B.bar");
		
		try{
			Thread.sleep(1000);
		} catch ( Exception e ) {
			System.out.println(" B interrupted");
		}
		
		System.out.println( name + " trying to call A.last()");
		a.last();
	}
	
	synchronized void last() {
		System.out.println("Inside A.last");
	}
	
}

public class DeadLock implements Runnable {
	
	A a = new A();
	B b = new B();
	
	DeadLock() {
		Thread.currentThread().setName("MainThread");
		Thread t = new Thread(this, "RacingThread");
		t.start();
		
		a.foo(b); // get lock on a in this thread
		System.out.println("Back in main thread");
	}
	
	public void run() {
		b.bar(a); // get lock on b in other thread
		System.out.println("Back in other thread");
	}
	
	public static void main ( String [] args) {
		new DeadLock();
	}
	
}

当运行这个程序的时候,会看到如下的输出

MainThread enter A.foo
RacingThread entered B.bar
RacingThread trying to call A.last()
MainThread trying to call B.last()

因为程序被死锁,所以你需要按下Ctrl+C 来结束程序。通过在PC上按下Ctrl + Break组合键,可以看到完整的线程和监视器缓存存储(monitor cache dump)。可以看出,在等待a的监视器时,竞态线程拥有b的监视器。同时,主线程拥有a,并且在等待获取b。这个程序永远不会结束。


所以,如果多线程程序偶尔被锁住,那么首先应当检查是否是由于死锁造成的

    原文作者:java锁
    原文地址: https://blog.csdn.net/tao20dage/article/details/50995144
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞