Как избежать тупика в Java? Это один из самых популярных вопросов интервью на Java, посвященный многопоточности, который задают в основном на старшем уровне и задают множество вопросов. Хотя вопрос выглядит очень простым, но большинство разработчиков Java застряли, когда вы начнете углубляться.
Вопросы интервью начинаются с «Что такое тупик?»
Ответ прост, когда два или более потоков ждут друг друга, чтобы освободить ресурс, который им нужен (блокировка) и застряли на бесконечное время, ситуация называется тупиком. Это произойдет только в случае многозадачности или многопоточности .
Как вы обнаруживаете тупик в Java?
Хотя это может иметь много ответов, моя версия — сначала, я бы посмотрел код, если я вижу вложенный синхронизированный блок или вызываю один синхронизированный метод из другого, или пытаюсь получить блокировку для другого объекта, тогда есть хороший шанс тупика если разработчик не очень осторожен.
Другой способ — найти его, когда вы фактически заблокированы во время работы приложения, попробуйте сделать дамп потока, в Linux вы можете сделать это командой «kill -3», это выведет на экран статус всех потоков в файле журнала приложения. и вы можете увидеть, какой поток заблокирован на каком объекте.
Вы можете проанализировать этот дамп потока с помощью таких инструментов, как fastthread.io, который позволяет загружать дамп потока и анализировать его.
Другой способ — использовать jConsole / VisualVM , он покажет вам, какие потоки заблокированы и на каком объекте.
Написать программу на Java, которая приведет к тупику?
Как только вы ответите на предыдущий вопрос, они могут попросить вас написать код, который приведет к тупику в Java?
Вот одна из моих версий:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
/** * Java program to create a deadlock by imposing circular wait. * * @author WINDOWS 8 * */public class DeadLockDemo { /* * This method request two locks, first String and then Integer */ public void method1() { synchronized (String.class) { System.out.println("Aquired lock on String.class object"); synchronized (Integer.class) { System.out.println("Aquired lock on Integer.class object"); } } } /* * This method also requests same two lock but in exactly * Opposite order i.e. first Integer and then String. * This creates potential deadlock, if one thread holds String lock * and other holds Integer lock and they wait for each other, forever. */ public void method2() { synchronized (Integer.class) { System.out.println("Aquired lock on Integer.class object"); synchronized (String.class) { System.out.println("Aquired lock on String.class object"); } } }} |
Если method1 () и method2 () оба будут вызваны двумя или несколькими потоками, существует высокая вероятность взаимоблокировки, потому что если поток 1 получает блокировку для объекта Sting при выполнении method1 (), а поток 2 получает блокировку для объекта Integer при выполнении method2 () оба будут ожидать друг друга, чтобы снять блокировку на Integer и String для продолжения, что никогда не произойдет.
Эта диаграмма точно демонстрирует нашу программу, где один поток удерживает блокировку одного объекта и ожидает блокировки других объектов, которые удерживаются другим потоком.
Вы можете видеть, что поток 1 хочет блокировки объекта 2, который удерживается потоком 2, а поток 2 хочет блокировки объекта 1, который удерживается потоком 1. Поскольку ни один поток не желает сдаваться, существует тупик, и Программа на Java застряла.
Как избежать тупика в Java?
Теперь интервьюер подходит к заключительной части, одной из самых важных на мой взгляд;
Как исправить тупик в коде? или как избежать тупика в Java?
Если вы внимательно изучили приведенный выше код, то, возможно, выяснили, что реальной причиной тупиковой ситуации являются не многопоточность, а способ, которым они запрашивают блокировку. Если вы предоставляете упорядоченный доступ, тогда проблема будет решена.
Вот моя фиксированная версия, которая позволяет избежать тупиковых ситуаций путем пустого кругового ожидания без прерывания , одно из четырех условий, которые необходимы для тупиковой ситуации.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
public class DeadLockFixed { /** * Both method are now requesting lock in same order, first Integer and then String. * You could have also done reverse e.g. first String and then Integer, * both will solve the problem, as long as both method are requesting lock * in consistent order. */ public void method1() { synchronized (Integer.class) { System.out.println("Aquired lock on Integer.class object"); synchronized (String.class) { System.out.println("Aquired lock on String.class object"); } } } public void method2() { synchronized (Integer.class) { System.out.println("Aquired lock on Integer.class object"); synchronized (String.class) { System.out.println("Aquired lock on String.class object"); } } }} |
Теперь не было бы никакой тупиковой ситуации, поскольку оба метода получают доступ к блокировке литерала класса Integer и String в одном и том же порядке. Таким образом, если поток A получает блокировку для объекта Integer, поток B не будет продолжаться до тех пор, пока поток A не снимет блокировку Integer, точно так же поток A не будет заблокирован, даже если поток B удерживает блокировку строки, поскольку теперь поток B не будет ожидать, что поток A освободит Целочисленная блокировка для продолжения.
Спасибо за чтение этой статьи. Если вам понравилась эта статья, пожалуйста, поделитесь с друзьями и коллегами. Если у вас есть какие-либо вопросы или пожелания, напишите нам.
| Смотрите оригинальную статью здесь: Как избежать тупика в Java Threads?
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |
