Deadlock how to do

Lock definition: Deadlock refers to two or more processes in the implementation process, due to the competition for resources or A blocking phenomenon caused due communicate with each other, without external force, they will not be able to promote it. Competitive resources can be: lock, network connections, disk sharing all variables can be called [resources] things.

We use locks to ensure thread safety, but improper use and misuse might lead to deadlock. Once concurrent programs deadlocks, generally we do not have particularly good way, and very often they restart. Therefore, we must avoid than deadlock.

A simple example

To give an example of inappropriate: Yue Buqun now available through intrigue to the book of the holy canon, then closed-door practice from the palace, and now he wants to continue to compete for the next volume of a train, or from the palace futile trip. This time next book is Lin Ping got, he would practice the holy canon, so the next book to find hidden on the books from the palace. Now the question is, Yue Buqun can not find the next book. Lin Ping can not get on the books, two people can only look on in despair who also refused to give his colleagues have to get the other side.

If at this time there is a thread A, according to first obtain a lock held by the lock b reacquisition order to obtain a lock, while another thread B, acquires the lock according to first obtain a lock latch b reacquisition order. As shown below: A thread is actually Yue Buqun, thread B is Lin Ping, holy canon two volumes are lockA, lockB

Deadlock

Then we use during code execution on analog line, using default environment SpringBoot

@Component
public class DeadLock {
    private static Object lockA = new Object();
    private static Object lockB = new Object();

    public void deadLock() {
        Thread threadA = new Thread(() -> {
            synchronized (lockA) {
                System.out.println(Thread.currentThread().getName() + "获取 lockA 成功");
                try {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println(Thread.currentThread().getName() + "尝试获取 lockB ");
                    synchronized (lockB) {
                        System.out.println(Thread.currentThread().getName() + "获取 lockB 成功");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
        Thread threadB = new Thread(() -> {
            synchronized (lockB) {
                System.out.println(Thread.currentThread().getName() + "获取 lockB 成功 ");
                try {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println(Thread.currentThread().getName() + "尝试获取 lockA ");
                    synchronized (lockA) {
                        System.out.println(Thread.currentThread().getName() + "获取 lockA 成功");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });

        threadA.start();
        threadB.start();
    }

}
复制代码

unit test

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
    @Autowired
    private DeadLock deadLock;

    @Test
    public void contextLoads() {
        deadLock.deadLock();
        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
复制代码

Console Print

Thread-4获取 lockB 成功 
Thread-3获取 lockA 成功
Thread-3尝试获取 lockB 
Thread-4尝试获取 lockA 
复制代码

We can see Thread-3 after acquiring lockA successful attempts to gain lockB been unsuccessful. Each waiting for the other to release the formation of a deadlock.

Deadlock checking

jstack instruction

The command can generate a snapshot of the virtual machine thread the current time. A snapshot is a set of threads battle every method currently executing thread, the main purpose is to locate the cause long pause threads appear, such as 线程间死锁, 死循环, 请求外部资源导致的长时间等待and so on.

First get the id of the process being executed by jps.

$ jps
23264 Jps
8472 JUnitStarter

复制代码

Jstack then view the current process stack information

$ jstack -F 8472
Attaching to process ID 8472, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.181-b13
Deadlock Detection:

Found one Java-level deadlock:
=============================

"Thread-4":
  waiting to lock Monitor@0x000000001f0134f8 (Object@0x00000007721d90f0, a java/lang/Object),
  which is held by "Thread-3"
"Thread-3":
  waiting to lock Monitor@0x000000001f011ef8 (Object@0x00000007721d90e0, a java/lang/Object),
  which is held by "Thread-4"

Found a total of 1 deadlock.

Thread 21: (state = BLOCKED)
 - com.zero.demo.deadlock.DeadLock.lambda$deadLock$1() @bci=79, line=35 (Interpreted frame)
 - com.zero.demo.deadlock.DeadLock$$Lambda$170.run() @bci=0 (Interpreted frame)
 - java.lang.Thread.run() @bci=11, line=748 (Interpreted frame)


Thread 20: (state = BLOCKED)
 - com.zero.demo.deadlock.DeadLock.lambda$deadLock$0() @bci=79, line=20 (Interpreted frame)
 - com.zero.demo.deadlock.DeadLock$$Lambda$169.run() @bci=0 (Interpreted frame)
 - java.lang.Thread.run() @bci=11, line=748 (Interpreted frame)

复制代码

Deadlock can be seen Found a total of 1 deadlock.

Deadlock Prevention

We know how to produce a deadlock, and then know how to prevent. If a thread can only acquire a lock, then a deadlock due to the nested sequence lead to holding the lock will not appear.

1. The correct order to get a lock

If you must acquire multiple locks, we must consider the different threads of lock acquisition order.

The root cause of the deadlock in the above example is to get the order is out of order, beyond our control. The above examples of the ideal situation is to put the business logic pulled out, to get inside the lock code in a public way for the two threads acquire locks

Are taken from the inside of my public way, when the thread enters Thread1 public methods, acquired A lock, in addition Thread2 they come in, but the lock has been Thread1 A thread acquired, we can only wait for obstruction. Thread1 went on to acquire the lock B, Thread2 thread lock can no longer get less than A, B, let alone go to acquire the lock, so there is a certain order. Only when the thread 1 releases all locks, thread B can get.

For example, the previous example we changed

@Component
public class DeadLock {
    private static Object lockA = new Object();
    private static Object lockB = new Object();

    public void deadLock() {
        Thread threadA = new Thread(() -> {
            getLock();
        });
        Thread threadB = new Thread(() -> {
            getLock();
        });

        threadA.start();
        threadB.start();
    }

    private void getLock() {
        synchronized (lockA) {
            System.out.println(Thread.currentThread().getName() + "获取 lockA 成功");
            try {
                TimeUnit.SECONDS.sleep(1);
                System.out.println(Thread.currentThread().getName() + "尝试获取 lockB ");
                synchronized (lockB) {
                    System.out.println(Thread.currentThread().getName() + "获取 lockB 成功");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

}

复制代码

Check the print result, we have found a thread 4 for success and then thread 3 to continue getting.

Thread-4获取 lockA 成功
Thread-4尝试获取 lockB 
Thread-4获取 lockB 成功
Thread-3获取 lockA 成功
Thread-3尝试获取 lockB 
Thread-3获取 lockB 成功
复制代码

2. overtime to give up

When a thread acquires the lock timeout is discarded, thus avoiding the deadlock acquisition occurs. When using the built-in lock synchronized keyword provided, as long as the thread does not get the lock, it will wait forever, but the Lock interface provides a boolean tryLock(long time, TimeUnit unit) throws InterruptedExceptionmethod, which can be a long wait for a lock according to fixed, so the thread can acquire the lock timeout after initiative release all locks previously obtained. In this way, it can also be very effective to avoid deadlocks.

Other Deadlock

Let's look at the definition of deadlock, "Deadlock refers to two or more processes in the implementation process, due to the competition for resources or A blocking phenomenon caused due communicate with each other, without external force, they are will not advance down. "deadlock condition inside the competition for resources, it can be a thread pool thread, connected to the network connection pool, lock data in the database engine provides, and so everything can be called things competing for resources.

Deadlock thread pool

final ExecutorService executorService = 
        Executors.newSingleThreadExecutor();
Future<Long> f1 = executorService.submit(new Callable<Long>() {

    public Long call() throws Exception {
        System.out.println("start f1");
        Thread.sleep(1000);//延时
        Future<Long> f2 = 
           executorService.submit(new Callable<Long>() {

            public Long call() throws Exception {
                System.out.println("start f2");
                return -1L;
            }
        });
        System.out.println("result" + f2.get());
        System.out.println("end f1");
        return -1L;
    }
});

复制代码

Type a single thread pool thread, but depend on the results of Task 1 Task 2, because the single-threaded mode, the task is not complete execution 1, Task 2 can never be executed, the deadlock.

to sum up

In my understanding among the deadlock it is "unreasonable to order two tasks compete for resources with each other" cause, so in order to avoid deadlock, the application needs to properly handle the order of resource acquisition. At other times, the deadlock will not be immediately reflected in the application out, under normal circumstances, are used in a production environment after running for a while, I began to slowly emerge in the actual testing process, because of a deadlock hidden, difficult to detect the presence of a deadlock in the testing process, but also in the production environment, the application appeared in a deadlock, often at the worst possible time application status - under high load conditions. Thus, developers in the development process to be careful analysis of each system resource usage, reasonable to avoid deadlock, the other once the deadlock, you can try to use some of the tools mentioned in this article, a careful analysis, always able to find the problem is located.

Public concern number JavaStorm forward regressed with thumbs up.

Guess you like

Origin juejin.im/post/5d3a6a8c5188252a7258c8ac
Recommended