What is a deadlock?

Official definition: 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).

Is it abstract? So what exactly is a deadlock? Let’s look at a real-life example:

There are two warehouses, warehouse A: Store iPhone; Warehouse B: Huawei mobile phones are stored in the warehouse. Every day at 4:00 PM, the staff will come to the warehouse to check the equipment condition. User A went to warehouse A and user B went to warehouse B, and they both got the keys of their respective warehouses. After entering warehouse A, user A checked and found that A HUAWEI P10 was placed in the warehouse that should have stored iiphone. User B checks in the warehouse and finds that an iPhone 8P is stored in the warehouse storing Huawei. At this time, both user A and user B need to return the misplaced phone to the corresponding warehouse. User A takes huawei P10 to the management office of warehouse B to get the key of warehouse B, and needs to put Huawei P10 into warehouse B. User B goes to the management office of warehouse A with iPhone 8P to get the key of warehouse A, and needs to put iPhone 8P into warehouse A. As the key of warehouse A is held by user A, and the key of warehouse B is held by user B, neither of them can get the key of each other. At this time, they will wait for the key to be returned at the management office. User waiting to use warehouse B sent back the keys (user B with warehouse B key), user B sent back, waiting for the key to the warehouse A (user A holding the key to A warehouse), obviously will not be returned, because they were in the other side of the management office, waiting for the other keys were sent back, because this is according to the world, if long time no one sent back to the key, So you can communicate by phone, and then get the key, but the program is not as smart as human, he will wait forever, that is, death, change to the program world, that is, deadlock. Note: it is not considered that the user takes out the phone and puts back the key before going to the other party’s warehouse. Otherwise, the condition is not valid. Now we have two accounts: account A and account B. Needs: 1. Same time. 2.A transfers 100 yuan to B, and B transfers 50 yuan to A (the amount is optional). 3. Add a mutex lock, such as synchronized, to each account. The general transfer process of A- >B is as follows: 1. Obtain the lock of account A (ensure that other modification operations on account A are blocked at this time). 2. Obtain the lock of account B to ensure that other operations to modify account B are blocked. 3. Make logical judgment, such as: whether the amount is enough, whether the amount is frozen, etc. 4.A’s account is deducted. 5.B add money to account. The general transfer process of A- >B is as follows: 1. Obtain the lock of account B (to ensure that other operations to modify account B are blocked at this time). 2. Obtain the lock of account A to ensure that other operations to modify account A are blocked. 3. Make logical judgment, such as: whether the amount is enough, whether the amount is frozen, etc. 4. Account of B is deducted. 5. Add money to account A.

There are two threads to perform the above two operations, thread 1 (perform A– >B transfer); Thread 2 (perform B– >A transfer), if thread 1 performs A– >B transfer) performs the first step (obtain the lock of account A), then the thread switches to thread 2 and performs B– >A transfer), performs the first step (obtain the lock of account B), then the thread is switched to thread 1 (perform A– >B transfer). Thread 1 (perform A– >B transfer) will be blocked until the lock of account B is released, switch to thread 2 (perform B– >A transfer), and perform the second step: The lock on account A (acquired by thread 1 (perform transfer A– >B)) is blocked, and thread 2 (perform transfer B– >A) is blocked. As A result, they will continue to block, resulting in A deadlock that cannot be released unless the program restarts. Note: synchronized is used here, otherwise the condition is not valid

Conditions under which a deadlock occurs

All four conditions are indispensable.

1. Mutual exclusion: ** indicates that a process (thread) uses the allocated resources exclusively. That is, only one process (thread) occupies a resource in a period of time. If another process (thread) requests the resource at this time, the requester can only wait until the process holding the resource is released. For example: Only one person can enter the warehouse, if the second person wants to enter, must wait for the previous person to come out

2. ** Request and hold conditions: ** refers to the process (thread) has held at least one resource, but puts forward a new resource request, and this resource has been occupied by another process (thread), the request process (thread) blocked, but it has obtained other resources hold. For example, after user A gets the key of warehouse A, user A tries to get the key of warehouse B. Meanwhile, user A cannot send the key of warehouse A back to the management office.

3. Non-deprivation condition: ** refers to the resource that the process (thread) has acquired, which cannot be deprived before it is used up. It can only be released by itself when it is used up. For example, after entering the warehouse, users need to count the number and model of mobile phones. They can not be taken away when they are not finished. They can only come out and return the keys after checking them.

4. Loop waiting conditions: ** indicates that there must be a process (thread) — resource loop chain when deadlock occurs, that is, P0 in process set {P0, P1, P2, ··· Pn} is waiting for a resource occupied by P1; P1 is waiting for resources occupied by P2,…… Pn is waiting for a resource that has been occupied by P0. For example, the above example of warehouse A and warehouse B is this condition

Recreate the deadlock with code

private static Account accountA = new Account();

    private static Account accountB = new Account();

    static {
        accountA.setId(1);
        accountA.setBalance(BigDecimal.valueOf(100));

        accountB.setId(2);
        accountB.setBalance(BigDecimal.valueOf(200));
    }

    /** * transfer */
    private static void transfer(BigDecimal num,Account account1, Account account2) {
        synchronized (account1) {
            Account a1 =account1;
            Account a2 = null;
            try {
                Thread 1 and thread 2 can acquire the lock of their own account while not acquiring the lock of the other account, so as to achieve the deadlock condition
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (account2) {
                a2 = account2;
            }
            if (a1.getBalance().compareTo(num) < 0) {
                System.out.println("Insufficient balance, transfer failed");
            }
            a1.setBalance(a1.getBalance().subtract(num));
            a2.setBalance(a2.getBalance().add(num));
            System.out.println("Transfer out account:" + a1);
            System.out.println("Transfer to account:"+ a2); }}public static void main(String[] args) {
        / / thread 1
        new Thread(() -> {
            transfer(BigDecimal.valueOf(10), accountA, accountB);
        }).start();

        / / thread 2
        new Thread(() -> {
            transfer(BigDecimal.valueOf(5), accountB, accountA);
        }).start();
    }
Copy the code

How do I check if this code is deadlocked? 1. View the output: If no information about accounts A and B is displayed, the system may be deadlocked. 2. Check the JVM for deadlocks. How do I look at the JVM? Here I introduce an idea plug-in: VisualVM Launcher

Use these two buttons to start the program and see what the JVM looks like.

How do I avoid deadlocks

Let’s first look at the conditions that cause deadlocks: 1. Mutual exclusion condition 2. Request and hold condition 3. 4. Loop wait condition

The first three conditions cannot be broken, so we only need to break the fourth condition. Here are a few ways to prevent deadlocks.

  1. Use interruptible locks:

    Lock provides tryLoc() when threads 1 and 2 both acquire their own locks and need to acquire the other lock. If the lock fails to acquire or is acquired within a specified period of time, you can manually interrupt the operation to prevent deadlocks.

  2. Acquire all resources at once (lock) : You can write a while loop that acquires both accounts’ locks (synchronized), marks both accounts’ locks as not being acquired, and then exits the loop, locking both accounts. Since the tag is read in a loop, the tag can be modified after the lock is released to allow the next thread to acquire the lock, which also prevents deadlocks.

  3. ** Sort locks: ** This is abstract, it is to acquire locks in descending or ascending order, and then from the smallest to the largest or from the largest to the smallest order. This also prevents deadlocks.

conclusion

Prevent deadlocks way still has a lot of, I simply introduces three here, then concurrent programming, a deadlock is relatively easy to encounter problems, how to avoid deadlock and how to avoid deadlock improve system performance are program ape what needs to be further studied, hope this article can help you to understand the deadlock.