What is a thread deadlock

A deadlock is a phenomenon in which two or more processes (threads) are blocked during execution, either by competing for resources or by communicating with each other, and cannot proceed without external action. The system is said to be in a deadlock state or the system has a deadlock. These processes (threads) that are always waiting for each other are called deadlocked processes (threads).

Multiple threads are blocked at the same time, and one or all of them are waiting for a resource to be released. Because the thread is blocked indefinitely, the program cannot terminate normally.

As shown in the figure below, thread A holds resource 2 and thread B holds resource 1. They both want to claim resources from each other at the same time, so the two threads wait for each other and enter A deadlock state.

The thread deadlock

To illustrate thread deadlocks, the code emulates the deadlock situation shown above

public class DeadLockDemo { private static Object resource1 = new Object(); Private static Object Resource2 = new Object(); private static Object resource2 = new Object(); Public static void main(String[] args) {new Thread(() -> {synchronized (resource1) { System.out.println(Thread.currentThread() +"get resource1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resource2");
                synchronized (resource2) {
                    System.out.println(Thread.currentThread() + "get resource2"); }}},Thread 1 "").start();
        new Thread(() -> {
            synchronized (resource2) {
                System.out.println(Thread.currentThread() + "get resource2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resource1");
                synchronized (resource1) {
                    System.out.println(Thread.currentThread() + "get resource1"); }}},Thread 2 "").start(); }}Copy the code

The output

Thread[Thread 1,5,main]get resource1 Thread[Thread 2,5,main]get resource2 Thread[Thread 1,5,main]waiting get resource2 Thread[Thread 2, 5, the main] waiting get resource1Copy the code

Thread A acquires the monitor lock of resource1 through synchronized (resource1) and thread.sleep (1000); Let thread A sleep for 1s so that thread B gets CPU execution and then the monitor lock for Resource2. When thread A and thread B sleep, they both attempt to request resources from each other, and then the two threads fall into A state of waiting for each other, resulting in A deadlock.

The above example meets the four necessary conditions for a deadlock to occur.

What are the four necessary conditions for a deadlock

1. Mutually exclusive conditions

Threads (processes) are exclusive to allocated resources, that is, a resource can only be occupied by one thread (process) until it is released by the thread (process)

2. Request and hold conditions

When a thread (process) is blocked due to a request for occupied resources, it holds on to acquired resources.

3. No deprivation of conditions

Resources acquired by a thread (process) cannot be forcibly taken away by other threads until they are used up. Resources can only be released after they are used up.

4. Cyclic wait conditions

When a deadlock occurs, the waiting thread (process) must form a loop (similar to an infinite loop), causing permanent blocking

How do I avoid thread deadlocks

We only have to break one of the four conditions that cause the deadlock.

1. Break the mutual exclusion condition

There is no way to break this condition because we use locks to make them mutually exclusive (critical resources require mutually exclusive access).

2. Break request and hold conditions

Apply for all resources at once.

3, destruction does not deprive conditions

When a thread that occupies some resources applies for other resources, it can release the occupied resources if it fails to apply for other resources.

4. Break the loop waiting condition

Prevention by sequentially requesting resources. Apply for resources in a certain order, and release resources in reverse order. Break the loop wait condition.

We changed the code for thread 2 to the following so that deadlocks would not occur.

new Thread(() -> {
    synchronized (resource1) {
        System.out.println(Thread.currentThread() + "get resource1");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread() + "waiting get resource2");
        synchronized (resource2) {
            System.out.println(Thread.currentThread() + "get resource2"); }}},Thread 2 "").start();
Copy the code

The output

Thread[Thread 1,5,main]get resource1Copy the code

Why does this code prevent deadlocks?

Thread 1 is the first to acquire the monitor lock of Resource1, at which point thread 2 cannot acquire it. Thread 1 then acquires the monitor lock for Resource2, which is available. Thread 1 then releases the monitor lock on resource1 and resource2, which thread 2 acquires and executes. This breaks the break loop wait condition, thus avoiding deadlocks.

This article is only for learning, copyright belongs to the original author, if there is infringement, please contact delete.

I’ve compiled the interview questions and answers in PDF files, as well as a set of learning materials covering, but not limited to, the Java Virtual Machine, the Spring framework, Java threads, data structures, design patterns and more.

Follow the public account “Java Circle” for information, as well as quality articles delivered daily.