Java Multithreading 7: Deadlock

Reprinted from: http://www.cnblogs.com/xrq730/p/4853713.html


foreword

Deadlock is written in a separate article because this is a very serious problem that must be paid attention to. This is not to overstate the risk of deadlock, although locks are usually held for a short period of time, an application as a commercial product may perform billions of lock acquisition -> release lock operations every day, as long as the A single error in an operation can lead to a deadlock in a program, and it is impossible to find all potential deadlocks even with a stress test.

 

deadlock

A classic multithreading problem.

When a thread holds a lock forever, and other threads try to acquire the lock, then they will be blocked forever, we all know that. If thread A holds lock L and wants to acquire lock M, and thread B holds lock M and wants to acquire lock L, then the two threads will wait forever, which is the simplest form of deadlock.

Deadlock monitoring and recovery from deadlock are considered in the design of the database system. If the database detects that a group of transactions is deadlocked, it will select a victim and give up the transaction. The Java virtual machine is not as powerful as the database in solving the deadlock problem. When a set of Java threads deadlocks, the two threads can never be used again, and because the two threads hold two locks, then this The two synchronized code/blocks can no longer run - unless the app is terminated and restarted.

Deadlock is a bug of design, and the problem is relatively obscure. However, the impact of deadlocks is rarely immediately apparent. The possibility of deadlocks in a class does not mean that deadlocks will occur every time, it just means that it is possible. When deadlocks occur, it's often in the worst-case scenario -- high load .

Here is a simple code that produces a deadlock and demonstrates how to analyze it as a deadlock:

copy code
public class DeadLock
{
    private final Object left = new Object();
    private final Object right = new Object();
    
    public void leftRight() throws Exception
    {
        synchronized (left)
        {
            Thread.sleep(2000);
            synchronized (right)
            {
                System.out.println("leftRight end!");
            }
        }
    }
    
    public void rightLeft() throws Exception
    {
        synchronized (right)
        {
            Thread.sleep(2000);
            synchronized (left)
            {
                System.out.println("rightLeft end!");
            }
        }
    }
}
copy code

Note that there must be "Thread.sleep(2000)" to let the thread sleep, otherwise one thread is running, and the other thread is not running, the thread that runs first is likely to have acquired two locks in a row. Write two threads to call them separately:

copy code
public class Thread0 extends Thread
{
    private DeadLock dl;
    
    public Thread0(DeadLock dl)
    {
        this.dl = dl;
    }
    
    public void run()
    {
        try
        {
            dl.leftRight();
        }
        catch (Exception e)
        {
            e.printStackTrace ();
        }
    }
}
copy code
copy code
public class Thread1 extends Thread
{
    private DeadLock dl;
    
    public Thread1(DeadLock dl)
    {
        this.dl = dl;
    }
    
    public void run()
    {
        try
        {
            dl.rightLeft();
        }
        catch (Exception e)
        {
            e.printStackTrace ();
        }
    }
}
copy code

Write a main function to call:

copy code
public static void main(String[] args)
{
    DeadLock dl = new DeadLock();
    Thread0 t0 = new Thread0(dl);
    Thread1 t1 = new Thread1(dl);
    t0.start();
    t1.start();

    while(true);   
}
copy code

As for the result, there is no result, no statement will be printed, because it is deadlocked. The following demonstrates how to locate the deadlock problem:

1. jps gets the pid of the current Java virtual machine process

 

2, jstack print stack. At the end of the print content of jstack, it has actually reported that a deadlock has been found, but because we are analyzing the cause of the deadlock, rather than directly getting the conclusion that there is a deadlock here, so leave it alone, just look at the previous part

Let's first explain the meaning of each part, taking "Thread-1" as an example:

(1) "Thread-1" represents the thread name

(2) "prio=6" indicates thread priority

(3) "tid=00000000497cec00" means thread Id

(4) not = 0x219c

The local thread Id corresponding to the thread, this is the key point. Because the Java thread is attached to the local thread in the Java virtual machine to run, in fact, the local thread is executing the Java thread code, and only the local thread is the real thread entity. When a thread is created in Java code, the virtual machine will create a corresponding local thread during runtime, and this local thread is the real thread entity. In the Linux environment, you can use "top -H -p JVM process Id" to view the local thread (also known as LWP) information under the JVM process. Note that this local thread is expressed in decimal, and nid is expressed in hexadecimal , just convert it, the local thread Id corresponding to 0x219c should be 8604.

(5) "[0x000000004a3bf000..0x000000004a3bf790]" indicates the memory address occupied by the thread

(6) "java.lang.Thread.State: BLOCKED" indicates the state of the thread

After explaining the meaning of each part, see that Thread-1 is in the BLOCKED state, and Thread-0 is in the BLOCKED state. Analyze these two threads:

(1) Thread-1 has obtained the lock 0x000000003416a4e8 and is waiting for the lock 0x000000003416a4d8

(2) Thread-0 has obtained the lock 0x000000003416a4d8 and is waiting for the lock 0x000000003416a4e8

Since both threads are waiting to acquire the lock held by the other, they wait forever.

3. Pay attention to the use of Eclipse/MyEclipse. If this program does not click the red box on the console to Terminate it, but right-click->Run As->1 Java Application, this process will always exist. At this time You can use the taskkill command to kill processes that have not been Terminated:

 

Ways to avoid deadlocks

Since deadlock may occur, then let's talk about how to avoid deadlock.

1. Let the program acquire at most one lock at a time. Of course, in a multithreaded environment this is usually not realistic

2. Consider the order of locks clearly when designing, and minimize the number of embedded locking interactions

3. Since the deadlock is caused by two threads waiting infinitely for the lock held by the other, it is better as long as the waiting time has an upper limit. Of course, synchronized does not have this function, but we can use the tryLock method in the Lock class to try to acquire the lock. This method can specify a timeout period and return a failure message after waiting for the timeout period.


Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326899684&siteId=291194637