Java Multithreading Study Notes - Nine, Deadlock in Java Multithreading

1, java object lock

        Every object in java has a unique lock. At any time, at most one thread is allowed to own the lock. The concept of locks comes into play when we use the synchronized keyword. 

2. Deadlock example

        The following is a sample reference code that is prone to deadlock, and it is not recommended to use an online IDE to run the above program. It is recommended to use the javac command to compile and then use the java command to run.

// Java program to illustrate Deadlock
// in multithreading.
class Util
{
	// Util class to sleep a thread
	static void sleep(long millis)
	{
		try
		{
			Thread.sleep(millis);
		}
		catch (InterruptedException e)
		{
			e.printStackTrace();
		}
	}
}

// This class is shared by both threads
class Shared
{
	// first synchronized method
	synchronized void test1(Shared s2)
	{
		System.out.println("test1-begin");
		Util.sleep(1000);

		// taking object lock of s2 enters
		// into test2 method
		s2.test2();
		System.out.println("test1-end");
	}

	// second synchronized method
	synchronized void test2()
	{
		System.out.println("test2-begin");
		Util.sleep(1000);
		// taking object lock of s1 enters
		// into test1 method
		System.out.println("test2-end");
	}
}


class Thread1 extends Thread
{
	private Shared s1;
	private Shared s2;

	// constructor to initialize fields
	public Thread1(Shared s1, Shared s2)
	{
		this.s1 = s1;
		this.s2 = s2;
	}

	// run method to start a thread
	@Override
	public void run()
	{
		// taking object lock of s1 enters
		// into test1 method
		s1.test1(s2);
	}
}


class Thread2 extends Thread
{
	private Shared s1;
	private Shared s2;

	// constructor to initialize fields
	public Thread2(Shared s1, Shared s2)
	{
		this.s1 = s1;
		this.s2 = s2;
	}

	// run method to start a thread
	@Override
	public void run()
	{
		// taking object lock of s2
		// enters into test2 method
		s2.test1(s1);
	}
}


public class Deadlock
{
	public static void main(String[] args)
	{
		// creating one object
		Shared s1 = new Shared();

		// creating second object
		Shared s2 = new Shared();

		// creating first thread and starting it
		Thread1 t1 = new Thread1(s1, s2);
		t1.start();

		// creating second thread and starting it
		Thread2 t2 = new Thread2(s1, s2);
		t2.start();

		// sleeping main thread
		Util.sleep(2000);
	}
}

        What does the above code do?

  1. Thread t1 starts and calls the test1 method by acquiring the object lock on s1.
  2. Thread t2 starts and calls the test1 method by acquiring the object lock on s2.
  3. t1 prints test1-begin and t2 prints test-2 begin and both wait 1 second, so if either thread doesn't start, both threads can start.
  4. t1 tries to acquire s2's object lock and calls the test2 method, but since it has already been acquired by t2, it waits until it becomes free. It will not release the lock on s1 until it acquires the lock on s2.
  5. The same is true for t2. It tries to acquire the object lock on s1 and calls method test1 but it has already been acquired by t1, so it has to wait until t1 releases the lock. t2 also does not release the lock of s2 until it acquires the lock of s1.
  6. Now, both threads are in a waiting state, waiting for the other to release the lock. There is now a race condition on who will release the lock first.
  7. Since none of them are ready to release the lock, this is a deadlock condition.
  8. When you run the program, it looks like execution is suspended.

3. View deadlock

        After running the code in the previous section, you can enter the windows details when the deadlock occurs, and you can see that two java threads are running.

         We can start another cmd window and run the jcmd $PID Thread.print command , where $PID is the thread id in the figure above.

        I enter jcmd 53364 Thread.print here and press Enter, and I will see the output clearly stating that a deadlock was found.

 4. Avoid deadlocks

        Avoid Nested Locks: This is the main cause of deadlocks. Deadlocks mainly occur when we lock multiple threads. Avoid locking multiple threads if we have given one thread.

        Avoid unnecessary locks: we should lock only those members that are needed. Unnecessary locking can lead to deadlocks.

        Using join: A deadlock situation occurs when one thread is waiting for another thread to finish. If this happens, we can use Thread.join and the maximum time you think it will take to execute.

Guess you like

Origin blog.csdn.net/bashendixie5/article/details/123599730