Deadlock

Imagine a tester and a developer are working on two applications, an Android application and an iPhone application. The Android application is in its testing phase; it should be tested and the reported bugs should be fixed by the developer. The iPhone application needs to be developed from scratch; it should be coded by the developer and then tested for bugs. Imagine the tester starts testing the Android application and the developer starts working with the iPhone application. The Android application completes the testing phase and requests for the developer to fix the bugs. At the same time, the iPhone application completes its development phase and requests the tester to test it. The managers working with both the Android and iPhone applications refuse to release their resources (developer or tester) before their project completes. So both projects are waiting for the other project to complete—that is, waiting for the same set of resources. This causes a deadlock—these threads might wait forever. Here’s how this looks in code:

Code Snippet :

package com.gs.corejava.collections;

class Developer {

	public synchronized void fixBugs() {
		System.out.println("Fixing bugs..");
	}

	public synchronized void code() {
		System.out.println("Coding..");
	}
}

class Tester {
	public synchronized void testAppIn() {
		System.out.println("Testing..");
	}
}

/**
 * Already developed , Hence first testing then fix bugs by dev team
 * 
 * @author momalhotra
 * 
 */
class AndroidApp implements Runnable {
	Developer developer;
	Tester tester;

	/**
	 * @param developer
	 * @param tester
	 */
	public AndroidApp(Developer developer, Tester tester) {
		super();
		this.developer = developer;
		this.tester = tester;
	}

	public void run() {
		synchronized (tester) {
			tester.testAppIn();
			developer.fixBugs();
		}
	}

}

/**
 * Starting development , then will be given to testing team
 * 
 * @author momalhotra
 * 
 */
class IphoneApp implements Runnable {
	Developer developer;
	Tester tester;

	/**
	 * @param developer
	 * @param tester
	 */
	public IphoneApp(Developer developer, Tester tester) {
		super();
		this.developer = developer;
		this.tester = tester;
	}

	public void run() {
		synchronized (developer) {
			developer.code();
			tester.testAppIn();
		}
	}

}

public class Deadlock {
	public static void main(String[] args) {
		Developer mohit = new Developer();
		Tester neeti = new Tester();

		Thread iphoneApp = new Thread(new IphoneApp(mohit, neeti));
		Thread androidApp = new Thread(new AndroidApp(mohit, neeti));

		iphoneApp.start();
		androidApp.start();
	}
}

Database Deadlocks

A more complicated situation in which deadlocks can occur, is a database transaction. A database transaction may consist of many SQL update requests. When a record is updated during a transaction, that record is locked for updates from other transactions, until the first transaction completes. Each update request within the same transaction may therefore lock some records in the database.

If multiple transactions are running at the same time that need to update the same records, there is a risk of them ending up in a deadlock.

For example

Transaction 1, request 1, locks record 1 for update
Transaction 2, request 1, locks record 2 for update
Transaction 1, request 2, tries to lock record 2 for update.
Transaction 2, request 2, tries to lock record 1 for update.

Since the locks are taken in different requests, and not all locks needed for a given transaction are known ahead of time, it is hard to detect or prevent deadlocks in database transactions.

Examples:

1)

package com.gs.corejava.collections;

public class Deadlock1 {

	public static void main(String[] args) {
		try {
			Thread.currentThread().join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

2)

package com.gs.corejava.collections;

public class Deadlock2 {

	static String s1 = "Mohit";
	static String s2 = "Neeti";

	public static void main(String[] args) {

		new Thread() {
			public void run() {
				synchronized (s1) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					synchronized (s2) {

					}
				}
			}
		}.start();

		new Thread() {
			public void run() {
				synchronized (s2) {
					synchronized (s1) {

					}
				}
			}
		}.start();

	}
}

Programmatically, You can detect the threads which have entered into deadlock condition and also you can retrieve the details about them. This can be done using ThreadMXBean interface of java.lang.Management package. You can go through the oracle docs of ThreadMXBean interface.

First, you have to get an instance of ThreadMXBean using getThreadMXBean() method of ManagementFactory, like this.

1

ThreadMXBean bean = ManagementFactory.getThreadMXBean();

After getting an instance of ThreadMXBean, call findMonitorDeadlockedThreads() method on it. It returns an array of type long containing ids of all currently deadlocked threads.

1

long ids[] = bean.findMonitorDeadlockedThreads();

After getting the ids of deadlocked threads, pass these ids to getThreadInfo() method of ThreadMXBean. It will return an array of ThreadInfo objects, where one ThreadInfo object contains the details of one deadlocked thread.

1

ThreadInfo threadInfo[] = bean.getThreadInfo(ids);

Iterate the ThreadInfo array to get the details of individual deadlocked thread.

for (ThreadInfo threadInfo1 : threadInfo){ System.out.println(threadInfo1.getThreadName()); //Prints the name of deadlocked thread

Example :

1)

package com.gs.corejava.collections;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;

public class Deadlock2 {

	static String s1 = "Mohit";
	static String s2 = "Neeti";

	public static void main(String[] args) {

		new Thread() {
			public void run() {
				synchronized (s1) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					synchronized (s2) {

					}
				}
			}
		}.start();

		new Thread() {
			public void run() {
				synchronized (s2) {
					synchronized (s1) {

					}
				}
			}
		}.start();

		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
		long[] ids = threadMXBean.findMonitorDeadlockedThreads();
		ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(ids);

		for (ThreadInfo info : threadInfos) {
			System.out.println(info);
		}
	}
}

2)

public class Deadlock {
	public static void main(String[] args) {
		Developer mohit = new Developer();
		Tester neeti = new Tester();

		Thread iphoneApp = new Thread(new IphoneApp(mohit, neeti));
		Thread androidApp = new Thread(new AndroidApp(mohit, neeti));

		iphoneApp.setName("Iphone App maker thread");
		androidApp.setName("Android App maker thread");
		iphoneApp.start();
		androidApp.start();

		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
		long[] ids = threadMXBean.findMonitorDeadlockedThreads();
		ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(ids);

		for (ThreadInfo info : threadInfos) {
			System.out.println(info);
		}
	}
}

Last updated