Как обнаружить нарушения синхронизации с Java

Мне интересно, какие хорошие способы будут делать утверждения о синхронизации или что-то, чтобы я мог обнаружить нарушения синхронизации (во время тестирования).

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

Я тоскую по что-то подобное, что можно было бы сделать для потока отправки AWT со следующим:

public static void checkDispatchThread() {
    if(!SwingUtilities.isEventDispatchThread()) {
        throw new RuntimeException("GUI change made outside AWT dispatch thread");
    }
}

Я хотел бы только что-то более общее. Описание проблемы не так ясно, но я надеюсь, что у кого-то есть хорошие подходы =)

9 ответов


вы ищете Святой Грааль, я думаю. AFAIK его не существует, и Java не является языком, который позволяет легко создать такой подход.

"параллелизм Java на практике"имеет раздел о тестировании проблем с потоками. Он обращает особое внимание на то, как трудно это сделать.


когда проблема возникает над потоками в Java, она обычно связана с обнаружением взаимоблокировки, больше, чем просто мониторинг того, какие потоки обращаются к синхронизированному разделу одновременно. JMX расширение, добавленное в JRE с 1.5, может помочь вам обнаружить эти тупики. На самом деле мы используем JMX внутри нашего собственного программного обеспечения для автоматического обнаружения блокировок трассировки, где она была найдена.

здесь пример о том, как использовать его.


IntelliJ IDEA имеет много полезного параллелизма инспекции. Например, он предупреждает вас, когда вы обращаетесь к одному и тому же объекту из синхронизированных и несинхронизированных контекстов, когда вы синхронизируетесь с не-конечными объектами и многое другое.

кроме того, в FindBugs есть много подобных проверки.


а также упоминание @Fernando о блокировке потоков, еще одна проблема с несколькими потоками-одновременные модификации и проблемы, которые это может вызвать.

одна вещь, которую Java делает внутренне, заключается в том, что класс коллекции сохраняет количество раз, когда он был обновлен. И затем итератор проверяет это значение на каждом .next () против того, что было, когда interator был создан, чтобы увидеть, была ли коллекция обновлена во время итерации. Я думаю, что этот принцип может использоваться более широко.


попробовать конкурс или Covertity

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

кроме того, проверьте этот вопрос:модульное тестирование многопоточного приложения?


вас может заинтересовать подход, о котором написал в блоге Питер Вентьер, который он называет Детектор Параллелизма. Я не верю, что у него есть открытый исходный код, но, как он описывает его, основная идея состоит в том, чтобы использовать AOP для инструментального кода, который вас интересует в профилировании, и записывать, какой поток коснулся какого поля. После этого необходимо вручную или автоматически проанализировать сгенерированные журналы.


Если вы можете определить небезопасные классы потоков, статический анализ может сказать вам, будут ли они когда-либо "escape", чтобы стать видимыми для нескольких потоков. Обычно программисты делают это в уме, но очевидно, что они склонны к ошибкам в этом отношении. Инструмент должен иметь возможность использовать аналогичный подход.

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

class Foo {

  private final Thread owner = Thread.currentThread();

  void x() {
    assert Thread.currentThread() == owner;
    /* Implement method. */
  }

}

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

на нить.holdsLock(объект) метод также может быть полезным для вас.


для конкретного примера, который вы даете, SwingLabs имеет некоторый вспомогательный код для обнаружения нарушений потока событий и зависаний. https://swinghelper.dev.java.net/

некоторое время назад я работал с инструментами профилирования java JProbe. Один из их инструментов (threadalyzer?) искал нарушения синхронизации потоков. Глядя на их веб-страницу, Я не вижу инструмента с таким именем или совсем то, что я помню. Но вы, возможно, захотите взглянуть. http://www.quest.com/jprobe/performance-home.aspx


можно использовать профилировщик Netbeans или утилиты jconsole чтобы проверить состояние потоков в глубину