This is the 13th day of my participation in the August More Text Challenge. For details, see:August is more challenging


What is a deadlock

What deadlocks are and how to avoid them in concurrent programs has always been a favored question for interviewers. This article uses the most concise example possible to help you quickly understand why deadlocks occur and how to resolve them. Before reading what follows, you must have a basic knowledge of how exclusive locks communicate with threads in Java.

Deadlock When thread A holds exclusive lock A and attempts to acquire exclusive lock B, and thread B holds exclusive lock B and attempts to acquire exclusive lock A, A deadlock occurs because thread A and thread B hold the lock each other needs.

Here is a very simple deadlock example to help you understand the definition of a deadlock.

public class DeadLockDemo {

    public static void main(String[] args) {
        / / thread a
        Thread td1 = new Thread(new Runnable() {
            public void run(){ DeadLockDemo.method1(); }});/ / thread b
        Thread td2 = new Thread(new Runnable() {
            public void run(){ DeadLockDemo.method2(); }}); td1.start(); td2.start(); } publicstatic void method1() {
        synchronized (String.class) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread A tries to get integer.class");
            synchronized (Integer.class) {

            }

        }
    }

    public static void method2() {
        synchronized (Integer.class) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread B tries to get string.class");
            synchronized (String.class) {

            }

        }
    }

}

//----------------
// Thread B tries to get string.class
// Thread A attempts to obtain integer.class
//....
/ /...
/ /..
/ /.
// Block indefinitely
Copy the code

How do I avoid deadlocks?

The textbook answer should be to analyze and summarize the following causes of deadlocks in combination with the philosopher’s dining [1] model, and conclude that “to avoid deadlocks is to break any one of several conditions that cause deadlocks”.

Four conditions (causes) that must be achieved to cause a deadlock:

  1. Mutual exclusion: a resource can only be used by one thread at a time.
  2. Request and hold condition: when a thread is blocked by a request for a resource, it holds on to a resource it has acquired.
  3. Non-deprivation condition: A thread cannot forcibly deprive resources it has acquired before it uses them up.
  4. Loop wait condition: A loop wait resource relationship is formed between several threads, head to tail.

However, the name of “philosopher’s Meal” is disgusting, and the above four conditions seem to be a mouthful, plus I’m a lazy person, so it’s really hard for me to recite them in an interview. We must find a way to simplify these four conditions! Thus, by analyzing each of the four deadlock conditions, we can draw the following four conclusions.

  1. Mutex — one of the characteristics of an exclusive lock.
  2. Request and hold conditions — a feature of an exclusive lock that an attempt to acquire a lock does not release an already held lock
  3. Non-deprivation condition — one of the characteristics of an exclusive lock.
  4. Loop wait condition -> the only deadlock condition that needs to be memorized.

Good job! The complex deadlock condition has been simplified, and now only the exclusive lock and the fourth condition need to be memorized.

So, faced with the question of how to avoid deadlocks, this is the answer! In concurrent programs, deadlock can be avoided by avoiding the occurrence of multiple threads holding exclusive locks needed by each other in logic.

Let’s resolve the deadlock example in section 1 and prove our conclusion by “breaking” the fourth deadlock condition.

ε…­ε››θΏεŠ¨

In the example above, the Demo runs smoothly because there is no longer any logic for thread A to hold the lock required by thread B, and thread B to hold the lock required by thread A.

public class DeadLockDemo2 {

    public static void main(String[] args) {
        / / thread a
        Thread td1 = new Thread(new Runnable() {
            public void run(){ DeadLockDemo2.method1(); }});/ / thread b
        Thread td2 = new Thread(new Runnable() {
            public void run(){ DeadLockDemo2.method2(); }}); td1.start(); td2.start(); } publicstatic void method1() {
        synchronized (String.class) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread A tries to get integer.class");
            synchronized (Integer.class) {
                System.out.println("Thread A gets integer.class");
            }

        }
    }

    public static void method2() {
        // No longer acquire the integer.class lock required by thread A.
        synchronized (String.class) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread B tries to get integer.class");
            synchronized (Integer.class) {
                System.out.println("Thread B gets integer.class"); }}}}/* ----------------- Thread a tries to obtain integer.class. Thread A tries to obtain integer.class. Thread B tries to obtain integer.class
Copy the code

conclusion

Whether the programmer can clearly explain the causes of deadlock in the interview, and give the solution to the deadlock, can reflect whether the programmer is clear in the face of concurrency problems, whether the foundation of concurrency is firmly mastered, and so on. And the logic of concurrent modules in real projects is often much more complex than the examples in this article, so it’s important to fully understand the points outlined in this article before writing concurrent applications, and remember that concurrent programming must be as conservative as possible without significantly affecting program performance.


If this article helped you, remember to like πŸ‘ collection and follow oh 😊, hope to like a lot more…

If there are any mistakes in this post, feel free to correct them in the comments section


The articles

  • ☞ Front end interview: HTTP and web topics
  • In 2021, the front end of the interview knowledge essential factory
  • July front – end high-frequency interview questions
  • How browsers work
  • Analyze the differences between TCP and UDP
  • Thorough understanding of browser caching mechanisms
  • How does JavaScript affect DOM tree building
  • JavaScript event Model
  • Learn more about modern Web browsers
  • Deploy the Nextjs project on a Linux Ali Cloud server
  • Snowpack – faster front-end build tool
  • Learn more about JavaScript memory leaks
  • Describe the hash mode and history mode of the front-end route
  • Use of BFC and IFC CSS styles
  • CSS Performance Optimization
  • Quickly write a prototype chain that satisfies you and your interviewer
  • CommonJS, AMD, CMD, ES6 Module
  • How WebPack works and the difference between Loader and Plugin
  • Interpret HTTP1 / HTTP2 / HTTP3