Примеры общих взаимоблокировок и живых блокировок в Java

Java задняя часть
  • Последовательный тупик: чрезмерная блокировка, в результате чего друг у друга удерживает блокировку, которую ожидает другая сторона, из-за порядка выполнения
  • Взаимная блокировка ресурсов: несколько потоков ожидают одного и того же ресурса.

Тупик из-за заказа вызова

public class Test {
    Object leftLock = new Object();
    Object rightLock = new Object();
    public static void main(String[] args) {
        final Test test = new Test();
        Thread a = new Thread(new Runnable() {
            @Override            public void run() {
               int i=0;
                while (i<10)
                {
                    test.leftRight();
                    i++;
                }
            }
        },"aThread");
        Thread b = new Thread(new Runnable() {
            @Override            public void run() {
                int i=0;
                while (i<10)
                {
                    test.rightleft();
                    i++;
                }
            }
        },"bThread");
        a.start();
        b.start();
    }

    public void leftRight(){
        synchronized (leftLock){
            System.out.println(Thread.currentThread().getName()+":leftRight:get left");
            synchronized (rightLock){
                System.out.println(Thread.currentThread().getName()+":leftRight:get right");
            }
        }
    }

    public void  rightleft(){
        synchronized (rightLock){
            System.out.println(Thread.currentThread().getName()+":rightleft: get right");
            synchronized (leftLock){
                System.out.println(Thread.currentThread().getName()+":rightleft: get left");
            }
        }
    }

}

Вывод после запуска следующий

aThread:leftRight:get left
bThread:rightleft: get right

Вы можете найти следы взаимоблокировки через jstack

"bThread" prio=5 tid=0x00007fabb2001000 nid=0x5503 waiting for monitor entry [0x000000011d54b000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at main.lockTest.Test.rightleft(Test.java:52)
    - waiting to lock <0x00000007aaee5748> (a java.lang.Object)
    - locked <0x00000007aaee5758> (a java.lang.Object)
    at main.lockTest.Test$2.run(Test.java:30)
    at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
    - None

"aThread" prio=5 tid=0x00007fabb2801000 nid=0x5303 waiting for monitor entry [0x000000011d448000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at main.lockTest.Test.leftRight(Test.java:43)
    - waiting to lock <0x00000007aaee5758> (a java.lang.Object)
    - locked <0x00000007aaee5748> (a java.lang.Object)
    at main.lockTest.Test$1.run(Test.java:19)
    at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
    - None

можно увидетьbThreadдержать замок0x00000007aaee5758, пока жду0x00000007aaee5748, но простоaThreadдержать замок0x00000007aaee5748и ждать0x00000007aaee5758, что приводит к тупику

тупик голодания потока

public class ExecutorLock {
    private static ExecutorService single=Executors.newSingleThreadExecutor();
    public static class AnotherCallable implements Callable<String>{

        @Override        public String call() throws Exception {
            System.out.println("in AnotherCallable");
            return "annother success";
        }
    }


    public static class MyCallable implements Callable<String>{

        @Override        public String call() throws Exception {
            System.out.println("in MyCallable");
            Future<String> submit = single.submit(new AnotherCallable());
            return "success:"+submit.get();
        }
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCallable task = new MyCallable();
        Future<String> submit = single.submit(task);
        System.out.println(submit.get());
        System.out.println("over");
        single.shutdown();
    }
}

Вывод выполнения - только одна строка

in MyCallable

Наблюдая за jstack, вы можете увидеть следующее

"main" prio=5 tid=0x00007fab3f000000 nid=0x1303 waiting on condition [0x0000000107d63000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007aaeed1d8> (a java.util.concurrent.FutureTask)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:425)
    at java.util.concurrent.FutureTask.get(FutureTask.java:187)
    at main.lockTest.ExecutorLock.main(ExecutorLock.java:32)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

   Locked ownable synchronizers:
    - None
..
"pool-1-thread-1" prio=5 tid=0x00007fab3f835800 nid=0x5303 waiting on condition [0x00000001199ee000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007ab0f8698> (a java.util.concurrent.FutureTask)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:425)
    at java.util.concurrent.FutureTask.get(FutureTask.java:187)
    at main.lockTest.ExecutorLock$MyCallable.call(ExecutorLock.java:26)
    at main.lockTest.ExecutorLock$MyCallable.call(ExecutorLock.java:20)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
    - <0x00000007aaeed258> (a java.util.concurrent.ThreadPoolExecutor$Worker)

Основной поток ожидает завершения FutureTask, а поток в пуле потоков также ожидает завершения FutureTask.
Как видно из реализации кода, основной поток закинул задачу А в пул потоков, а задача А закинула задачу Б в тот же пул потоков, и дождалась завершения В. Так как в пуле всего один поток пул потоков, это будет В результате B застрянет в очереди на блокировку, а A должен дождаться завершения B, а значит, ожидание друг друга приводит к возрождению тупика.

Это явление блокировки из-за того, что выполняющиеся потоки задач ожидают задач в других рабочих очередях, называется взаимоблокировкой голодания потока.

живой замок

Блокировки потока нет, но выполнение не может продолжаться из-за наличия какой-то проблемы.

  1. Повтор сообщения. Когда сообщение не может быть обработано, оно все время повторяется, но по какой-то причине синтаксический анализ завершается сбоем из-за неправильного формата сообщения, и оно повторяется снова.

    В это время, как правило, необходимо не повторять неисправимые ошибки или ограничивать количество повторных попыток.

  2. Потоки, которые взаимодействуют друг с другом, реагируют друг на друга, чтобы изменить свое состояние, что приводит к сбою выполнения. Например, два очень вежливых человека встречаются на одной дороге, уступают друг другу дорогу, но снова встречаются на той же дороге. неоднократно избегайте друг друга

    В это время вы можете выбрать случайную уступку, чтобы она имела определенную случайность