Подтвердить что ты не робот

Советы по предотвращению взаимоблокировок в java

Я изучаю потоки java и взаимоблокировки, я понимаю примеры взаимоблокировок, но мне интересно, есть ли общие правила для предотвращения этого.

Мой вопрос в том, есть ли правила или советы, которые могут быть применены к исходному коду в java для предотвращения взаимоблокировок? Если да, не могли бы вы объяснить, как его реализовать?

4b9b3361

Ответ 1

Несколько быстрых советов из головы

  • не использовать несколько потоков (например, Swing делает, например, путем указания того, что все сделано в EDT)
  • не удерживать сразу несколько замков. Если вы это сделаете, всегда приобретайте блокировки в том же порядке
  • не выполнять внешний код при удерживании блокировки
  • использовать прерывистые блокировки

Ответ 2

Инкапсулировать, инкапсулировать, инкапсулировать! Вероятно, самая опасная ошибка, которую вы можете сделать с помощью блокировок, - это разоблачение вашей блокировки в мире (что делает ее общедоступной). Невозможно сказать, что может произойти, если вы сделаете это, так как любой сможет получить блокировку без знания объекта (поэтому вы не должны блокировать this). Если вы оставите свою блокировку конфиденциальной, тогда у вас есть полный контроль, и это делает ее более управляемой.

Ответ 3

  • Избегайте блокировок, используя блокирующие структуры данных (например, используйте ConcurrentLinkedQueue вместо синхронизированного ArrayList)
  • Всегда приобретайте блокировки в том же порядке, например. назначить уникальное числовое значение для каждого замка и получить блокировки с более низким численным значением до получения блокировок с более высоким численным значением.
  • Отпустите блокировки после периода ожидания (технически это не предотвращает взаимоблокировки, это просто помогает разрешить их после того, как они произошли)

Ответ 4

  • Не используйте блокировки.
  • Если вам нужно, держите свои локальные блоки. Глобальные блокировки могут быть очень сложными.
  • Сделайте как можно меньше, удерживая замок.
  • Используйте stripes только для блокировки сегментов ваших данных.
  • Предпочитают Неизменяемые типы. Много раз это означает копирование данных вместо совместного использования данных.
  • Вместо этого используйте сравнение и набор (CAS), см. AtomicReference.

Ответ 5

Прочитайте и поймите Java: Concurrency и Practice. Речь идет не о "советах", чтобы избежать тупиковой ситуации. Я бы никогда не нанял разработчика, который знал несколько советов, чтобы избежать тупика и часто избегал тупика. Это о понимании concurrency. К счастью, существует всеобъемлющая книга промежуточного уровня по этой теме, поэтому читайте ее.

Ответ 6

Учитывая выбор дизайна, используйте передачу сообщений, где только блокировки находятся в очереди push/pop. Это не всегда возможно, но если это так, у вас будет очень мало тупиков. Вы все равно можете их получить, но вам нужно очень стараться:)

Ответ 7

Существует почти одно правило, когда дело доходит до предотвращения взаимоблокировок:

Если вам нужно иметь несколько блокировок в коде, убедитесь, что все они всегда приобретают их в том же порядке.

Сохранение вашего кода без блокировок должно всегда быть вашей целью. Вы можете попытаться избавиться от них, используя неизменяемые или поточно-локальные объекты и блокированные структуры данных.

Ответ 8

Это классический пример тупика:

public void methodA(){

  synchronized(lockA){
  //...

   synchronized(lockB){
   //...
  }
 }
}

public void methodB(){

  synchronized(lockB){
  //...

   synchronized(lockA){
   //...
   }
  }
}

Эти методы, вероятно, создадут большой тупик, если будут вызваны многие потоки. Это происходит потому, что объекты заблокированы в разных порядках. Это одна из самых распространенных причин блокировок, поэтому, если вы хотите их избежать, убедитесь, что блокировки реализованы в порядке.

Ответ 9

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

  • Заблокируйте только то, что требуется. Как блокировать конкретное поле объекта, а не блокировать весь объект, если он служит вашей цели.

  • Не ждите бесконечно.

Ответ 10

  • Если не требуется, не обменивайтесь данными по нескольким потокам. Если данные не могут быть изменены после создания/инициализации, придерживайтесь конечных переменных.
  • Если вы не можете избежать совместного использования данных между несколькими потоками, используйте гранулированные блоки synchronized или Lock s.
  • Если вы используете только блоки кода synchronized, убедитесь, что блокировки получены/выпущены в определенном порядке.
  • Посмотрите на другие альтернативы: volatile или AtomicXXX или Lock API

Связанные вопросы SE:

Избежать синхронизации (это) в Java?

Разница между изменчивой и синхронизированной в Java

Volatile boolean vs AtomicBoolean

Ответ 11

  • Избегайте вложенных замков
  • Избегайте ненужных замков
  • Использовать нить join()

Ответ 12

Deadlock в Java - это ситуация программирования, когда два или более потоков блокируются навсегда. Ситуация взаимоблокировки Java возникает как минимум с двумя потоками и двумя или более ресурсами.

Как обнаружить тупик в Java

Чтобы обнаружить взаимоблокировку в Java, нам нужно взглянуть на дамп java-потока приложения, мы можем сгенерировать дамп потока, используя профилировщик VisualVM или утилиту jstack.

Для анализа взаимоблокировки нам нужно найти потоки с состоянием BLOCKED, а затем ресурсы, ожидающие блокировки. Каждый ресурс имеет уникальный идентификатор, с помощью которого мы можем определить, какой поток уже удерживает блокировку объекта.

Как избежать тупика в Java

Вот некоторые из руководств, с помощью которых мы можем избежать большинства тупиковых ситуаций.

  • Избегайте тупиковых ситуаций, нарушая условие циклического ожидания. Чтобы сделать это, в коде может быть организовано наложение порядка на получение и снятие блокировок. Если блокировка будет получена в согласованном порядке и снята в противоположном порядке, не будет ситуации, когда один поток удерживает блокировку, полученную другим, и наоборот.
  • Избегайте вложенных блокировок : это наиболее распространенная причина тупиковых ситуаций, избегайте блокирования другого ресурса, если он у вас уже есть. Почти невозможно получить тупиковую ситуацию, если вы работаете только с одной блокировкой объекта.
  • Блокировка только того, что требуется: вы должны получить блокировку только для ресурсов, с которыми вам нужно работать, если мы заинтересованы только в одном из его полей, то мы должны заблокировать только это конкретное поле, а не завершенный объект.
  • Избегайте бесконечного ожидания: вы можете получить взаимоблокировку, если два потока ждут друг друга бесконечного завершения с помощью объединения потоков. Если вашему потоку приходится ждать завершения другого потока, всегда лучше использовать соединение с максимальным временем ожидания завершения потока.