Java geek

Related reading:

Java Concurrent programming (1) Knowledge map Java concurrent programming (2) Atomic Java concurrent programming (3) Visibility Java concurrent programming (4) Sequential Java concurrent programming (5) Introduction to Creating threads Java concurrent programming (6) Synchronized usage Introduction to Concurrent Programming in Java (7) Easy to understand wait and Notify and application scenarios Introduction to Concurrent programming in Java (8) Thread lifecycle Introduction to Concurrent programming in Java (10) Lock optimization Introduction to Concurrent programming in Java (11) Flow limiting scenarios and Spring Flow limiter implementation Introduction to Concurrent Programming in Java (12) Producer and Consumer pattern – Introduction to concurrent programming in Java (13) Read/write lock and cache template (14) CountDownLatch Application Scenario Java Concurrent programming (15) CyclicBarrier application scenario Introduction to Concurrent programming in Java (16) seconds to understand the difference between the thread pool Java Concurrent programming introduction (17) one picture master common classes and interfaces for threads Java concurrent programming introduction (18) Again on thread safety Java concurrent programming introduction (19) Asynchronous task scheduling tool CompleteFeature Java Concurrent programming introduction (20) Common locking scenarios and locking tools


Deadlock conditions

Deadlock: A “permanent” block in which a group of threads competing for resources wait for each other.

The following deadlock conditions are met: 1. The shared resources X and Y can be occupied by only one thread. 2. Hold and wait. Thread T1 has acquired shared resource X and does not release shared resource X while waiting for shared resource Y. 3. Non-preemption. Other threads cannot forcibly preempt resources occupied by thread T1. 4. Loop wait. Thread T1 waits for resources occupied by thread T2, and thread T2 waits for resources occupied by thread T1.

Deadlocks occur when all four conditions are met, so you can avoid deadlocks by breaking just one of them.

Methods to avoid deadlocks

1. Mutual exclusion cannot be broken because locks are mutually exclusive. 2. For possession-and-wait, multiple resource locks X and Y can be acquired at the same time, so that there is no need to wait for Y to acquire X. This approach is only used when there are a small number of resource locks to be acquired, which is not feasible if there are a large number of resource locks to be acquired (for example, 10). 3. For non-preemption, some resources can be obtained. If other resources cannot be obtained, the obtained resources are released. This means that the operation cannot be handled as expected, and you need to consider how to handle the exception, such as whether to retry. 4. For circular waiting, you can sort the lock resources that need to be acquired and obtain them in sequence, so that multiple threads do not cross acquire the same resource and cause deadlock, but wait until the same resource is released.

To sum up, for scenarios that are prone to deadlocks, the processing is as follows: 1. Acquire a lock with a timeout period, and give up if you fail to obtain it. In this way, deadlock can be avoided in the simplest way, which also means that synchronized keyword cannot be used to acquire lock resources. 2. Add an active release mechanism for acquired lock resources. 3. Add exception processing, such as retry, when the lock resource is abandoned. 4. Multiple lock resources that need to be obtained can be sorted to avoid deadlocks to a certain extent. However, if deadlocks are not sorted, the process fails for the first time and may fail again during retries.

Three, deadlock bit

1. Simulate deadlock code

package com.javashizhan.concurrent.demo.deadlock;

/ * * *@ClassName DeadlockDemo
 * @Description TODO
 * @AuthorSonorous leaf *@Date 2019/10/3 23:40
 * javashizhan.com
 **/
public class DeadlockDemo {
    public static void main(String[] args) {
        // Create two objects for locking
        final Object lockX = new Object();
        final Object lockY = new Object();

        System.out.println("lockX " + lockX);
        System.out.println("lockY " + lockY);

        Thread tX = new Thread(new Worker(lockX, lockY), "tX");
        // Swap the order of locks to simulate deadlocks
        Thread tY = new Thread(new Worker(lockY, lockX), "tY"); tX.start(); tY.start(); }}class Worker implements Runnable {

    private final Object lockX;

    private final Object lockY;

    public Worker(Object lockX, Object lockY) {
        this.lockX = lockX;
        this.lockY = lockY;
    }

    public void run(a) {
        synchronized (lockX) {
            // Sleep for a while and wait for another thread to fetch the lockY
            sleep(2000);
            System.out.println(Thread.currentThread().getName() + " get lock " + lockX);

            synchronized (lockY) {
                // This step will never be executed due to a deadlock
                System.out.println(Thread.currentThread().getName() + " get lock "+ lockY); }}}private void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch(InterruptedException e) { e.printStackTrace(); }}}Copy the code

2. Logs generated by running the program

lockX java.lang.Object@28d93b30
lockY java.lang.Object@1b6d3586
tX get lock java.lang.Object@28d93b30
tY get lock java.lang.Object@1b6d3586
Copy the code

You can see that after each thread acquires a lock, a deadlock occurs and the execution does not proceed.

3. JPS View Java processes

4. Jstack View the stack information about the Java process. The key parts are as follows:


Solve the deadlock problem

For this example, deadlocks occur because two locks are dependent on each other in a loop. According to the method described above to avoid deadlocks, you can simply sort the locks as follows:

    public Worker(Object lockX, Object lockY) {
        int result = lockX.toString().compareTo(lockY.toString());
        this.lockX = result == -1 ? lockX : lockY;
        this.lockY = result == -1 ? lockY : lockX;
    }
Copy the code

Program execution log after code modification:

lockX java.lang.Object@28d93b30
lockY java.lang.Object@1b6d3586
tX get lock java.lang.Object@1b6d3586
tX get lock java.lang.Object@28d93b30
tY get lock java.lang.Object@1b6d3586
tY get lock java.lang.Object@28d93b30
Copy the code

After the lock is sorted, only one thread can acquire all the locks and execute them, the other thread can acquire the locks. Deadlock problem solved.

end.


<– Read the mark, left like!