Java, threads deadlocked?

北城以北 提交于 2019-12-24 08:49:34

问题


One of my friends showed me his code below, and I thought the two threads could be deadlocked, because they could deadlock while trying to acquire locks on the different variables: sb1 and sb2.

When I run the code, they don't seem to be deadlocked, as I was able to see the output:

A
B
second thread: AB
second thread: BA

Code below:

public static void main(String[] args) {
        StringBuilder sb1 = new StringBuilder();
        StringBuilder sb2 = new StringBuilder();

        new Thread() {
            public void run() {
                synchronized (sb1) {
                    sb1.append("A");
                    synchronized (sb2) {
                        sb2.append("B");
                        System.out.println(sb1.toString());
                        System.out.println(sb2.toString());
                    }
                }
            }
        }.start();

        new Thread() {
            public void run() {
                synchronized (sb2) {
                    sb2.append("A");
                    synchronized (sb1) {
                        sb1.append("B");
                        System.out.println("second thread: " + sb1.toString());
                        System.out.println("second thread: " + sb2.toString());
                    }
                }
            }
        }.start();
    }

so could the two threads be deadlocked?


回答1:


The fact that you are not getting a deadlock does not imply a deadlock cannot occur.

You are right in inferring that a deadlock might occur when two threads attempt to acquire monitors on two different resources in opposite orders.

Therefore, this code may produce a deadlock.

However, if any of the two threads manages to acquire both the monitors before the other, no deadlock will occur (which seems to be happening with your execution).

Here's how a deadlock might occur instead:

  1. Thread one starts and acquires lock on sb1
  2. Thread two starts and acquires lock on sb2
  3. Thread one waits to acquire lock on sb2, which is owned by thread two
  4. Thread two waits to acquire lock on sb1, which is owned by thread one

As no thread will release its lock and both wait on the other, you get a deadlock.

Note: as Khelwood advises, forcing the threads to sleep may prevent one of the threads from acquiring both locks first, hence producing the deadlock.




回答2:


The code you posted has a potential deadlock. If it runs successfully, that just means you got lucky.

To demonstrate the potential deadlock, you can rig the timing to ensure that a deadlock occurs.

public static void main(String[] args) {
    final StringBuilder sb1 = new StringBuilder();
    final StringBuilder sb2 = new StringBuilder();

    new Thread() {
        public void run() {
            synchronized (sb1) {
                sb1.append("A");
                System.out.println("Thread 1 has sync sb1");
                try { Thread.sleep(700); }
                catch (InterruptedException e) { e.printStackTrace(); return; }
                System.out.println("Waiting for thread 1 to sync sb2");
                synchronized (sb2) {
                    sb2.append("B");
                    System.out.println(sb1.toString());
                    System.out.println(sb2.toString());
                }
            }
        }
    }.start();

    new Thread() {
        public void run() {
            try { Thread.sleep(500); }
            catch (InterruptedException e) { e.printStackTrace(); return; }
            synchronized (sb2) {
                System.out.println("Thread 2 has sync sb2");
                sb2.append("A");
                System.out.println("Waiting for thread 2 to sync sb1");
                synchronized (sb1) {
                    sb1.append("B");
                    System.out.println("second thread: " + sb1.toString());
                    System.out.println("second thread: " + sb2.toString());
                }
            }
        }
    }.start();
}

Now the first thread will definitely get the sync on sb1, and the second will get the sync on sb2, and then you will get a deadlock.

Output:

Thread 1 has sync sb1
Thread 2 has sync sb2
Waiting for thread 2 to sync sb1
Waiting for thread 1 to sync sb2



回答3:


That code explains exactly a simple deadlock.

The easiest way to tell is basically because your Threads hold circular dependencies between each other.

This code alot of the times will result in a deadlock.




回答4:


Yes, your program can end in a deadlock. Here a more dynamic example based on the answer of @khelwood. It adds some delay to the actual string appending and repeats it in a while loop. So you can see what is happening, sooner or later the program will end in a deadlock. To identify the deadlock situation ThreadMXBean.findDeadlockedThreads() is used.

package stack43323164;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.util.List;

import java.lang.management.ThreadInfo;

public class HowToDemonstrateDeadlock {

    private static List<ThreadInfo> findDeadlocks() {
        ThreadMXBean tmxb = ManagementFactory.getThreadMXBean();
        long[] result = tmxb.findDeadlockedThreads();
        if (result == null)
            return java.util.Collections.emptyList();
        return java.util.Arrays.asList(tmxb.getThreadInfo(result, 2));
    }

    public static void main(String[] args) {

        final StringBuilder sb1 = new StringBuilder();
        final StringBuilder sb2 = new StringBuilder();

        long monitorDelay=1000L;
        //You can play with the delay times to modify the results
        long threadOneDelay=100L;
        long threadTwoDelay=100L;

        new Thread() {
            public void run() {
                try {
                    while (true) {
                        synchronized (sb1) {
                            sb1.append("A");
                            System.out.println("Thread 1 has sync sb1");
                            System.out.println("Waiting for thread 1 to sync sb2");
                            synchronized (sb2) {
                                sb2.append("B");
                                System.out.println(sb1.toString());
                                System.out.println(sb2.toString());
                            }
                        }
                        Thread.sleep(threadOneDelay);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();

        new Thread() {
            public void run() {
                try {
                    while (true) {
                        synchronized (sb2) {
                            System.out.println("Thread 2 has sync sb2");
                            sb2.append("A");
                            System.out.println("Waiting for thread 2 to sync sb1");
                            synchronized (sb1) {
                                sb1.append("B");
                                System.out.println("second thread: " + sb1.toString());
                                System.out.println("second thread: " + sb2.toString());
                            }
                        }
                        Thread.sleep(threadTwoDelay);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();

        new Thread() {
            public void run() {
                try {
                    while (true) {
                        List<ThreadInfo> deadlocks = findDeadlocks();
                        if (!deadlocks.isEmpty()) {
                            for (ThreadInfo i : deadlocks) {
                                System.out.println("Deadlock detected on thread " + i.getThreadId() + "\n" + i);
                            }
                            //Not a chance to solve the situation - boom
                            System.exit(1);
                        } else {
                            System.out.println("No deadlock so far.");
                        }
                        Thread.sleep(monitorDelay);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}


来源:https://stackoverflow.com/questions/43323164/java-threads-deadlocked

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!