如何在Java中创建死锁

时间:2020-01-09 10:35:30  来源:igfitidea点击:

如果询问我们什么是Java死锁,那么几乎总是伴随着如何在Java中创建死锁的问题。

多线程中的死锁是一种情况,其中两个或者更多线程正在彼此等待释放资源以取得进一步的进展,并在此过程中永远被阻塞。

用于创建死锁的Java程序

当嵌套的同步块具有相反的对象顺序时,我们可能会在Java中陷入僵局。

在示例中,创建了两个线程来运行两个单独的可运行任务。在每个可运行的任务中,都有嵌套的同步块以相反的顺序获取对象锁,从而产生了死锁。

class ThreadA implements Runnable{
	private Object obj1;
	private Object obj2;
	ThreadA(Object obj1, Object obj2){
		this.obj1 = obj1;
		this.obj2 = obj2;
	}
	@Override
	public void run() {
		synchronized(obj1){
			System.out.println(Thread.currentThread().getName() + " acquired " + "obj1 lock");
			System.out.println(Thread.currentThread().getName() + " waiting for " + "obj2 lock");
			synchronized(obj2){
				System.out.println(Thread.currentThread().getName() + " acquired " + "obj2 lock");
			}
		}       
	}  
}
 
class ThreadB implements Runnable{
	private Object obj1;
	private Object obj2;
	ThreadB(Object obj1, Object obj2){
		this.obj1 = obj1;
		this.obj2 = obj2;
	}
	@Override
	public void run() {
		synchronized(obj2){
			System.out.println(Thread.currentThread().getName() + " acquired " + "obj2 lock");
			System.out.println(Thread.currentThread().getName() + " waiting for " + "obj1 lock");
			synchronized(obj1){
				System.out.println(Thread.currentThread().getName() + " acquired " + "obj1 lock");
			}
		}   
	}
}

public class DLDemo {
	public static void main(String[] args) {
		Object obj1 = new Object();
		Object obj2 = new Object();
		Thread t1 = new Thread(new ThreadA(obj1, obj2));
		Thread t2 = new Thread(new ThreadB(obj1, obj2));
		t1.start();
		t2.start();
	}
}

输出:

Thread-0 acquired obj1 lock
Thread-0 waiting for obj2 lock
Thread-1 acquired obj2 lock
Thread-1 waiting for obj1 lock

我们可以在ThreadA的run()方法中看到,同步块获取obj1的锁,然后尝试获取obj2的锁。 ThreadB同步块的run()方法中的方法相同,它获取对obj2的锁定,然后尝试获取对obj1的锁定。当t1线程正在等待获取当前由t2线程获取的obj2上的锁,而t2线程正在等待获取当前由t1线程获取的obj1上的锁时,这会通过创建死锁来挂起程序。

通过从另一个调用一个同步方法来创建死锁

这是在Java中创建死锁的另一个示例。它与此处的第一个示例类似,而不是具有嵌套的同步块,而是有两种同步方法。用于调用该方法的对象和作为参数传递给这些方法的对象被颠倒,从而产生死锁。

public class DLDemo {
	public synchronized void method1(DLDemo obj){
		System.out.println(Thread.currentThread().getName() + " In Method1");
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//Calling another synchronized method
		obj.method2(this);
	 }
			  
	 public synchronized void method2(DLDemo obj2){
		 System.out.println("In Method2");
	 }
 
	public static void main(String[] args) {
		DLDemo obj1 = new DLDemo();
		DLDemo obj2 = new DLDemo();
	 
		new Thread(new Runnable() {
			public void run() { obj1.method1(obj2); }
		}).start();

		//Thread 2  
		new Thread(new Runnable() {
			public void run() { obj2.method1(obj1); }
		}).start();
	}
}

输出:

Thread-0 In Method1
Thread-1 In Method1

从一个线程使用obj1调用同步方法method1,因此该线程获取obj1的锁,然后使用obj2调用另一同步方法method2.
从另一个线程使用obj2调用同步方法method1,因此该线程获取obj2的锁,然后使用obj1调用另一个同步方法method2.