Как обнаружить нарушения синхронизации с Java
-
08-07-2019 - |
Вопрос
Мне интересно, как можно было бы сделать утверждения о синхронизации или что-то подобное, чтобы я мог обнаружить нарушения синхронизации (во время тестирования).
Это можно использовать, например, для случая, когда у меня будет класс, который не является поточно-ориентированным и не будет поточно-ориентированным. Каким-то образом у меня было бы какое-то утверждение, которое сообщало бы мне (журнал или что-то еще), если какой-то метод (ы) этого был вызван из нескольких потоков.
Я жажду чего-то подобного, что можно сделать для потока рассылки AWT со следующим:
public static void checkDispatchThread() {
if(!SwingUtilities.isEventDispatchThread()) {
throw new RuntimeException("GUI change made outside AWT dispatch thread");
}
}
Я бы хотел чего-то более общего. Описание проблемы не очень понятно, но я надеюсь, что у кого-то есть хорошие подходы =)
Решение
Я думаю, вы ищете святой Грааль. AFAIK его не существует, и Java не является языком, который позволяет легко создать такой подход.
" Параллелизм Java на практике " есть раздел по тестированию на проблемы с многопоточностью. Он обращает особое внимание на то, как трудно это сделать.
Другие советы
Когда возникает проблема с потоками в Java, она обычно связана с обнаружением взаимоблокировки, а не просто с отслеживанием того, какие потоки одновременно получают доступ к синхронизированному разделу. расширение JMX , добавленное в JRE начиная с версии 1.5, может помочь вы обнаруживаете эти тупики. Фактически мы используем JMX внутри нашего собственного программного обеспечения, чтобы автоматически обнаруживать тупики трассировки, где она была найдена. Р>
Вот пример о том, как его использовать.
IntelliJ IDEA имеет много полезного параллелизма проверки . Например, он предупреждает вас, когда вы обращаетесь к одному и тому же объекту как из синхронизированного, так и из несинхронизированного контекста, когда вы синхронизируете неконечный объект и т. Д.
Помимо упоминания @ Fernando о взаимоблокировке потоков, еще одна проблема с несколькими потоками - это одновременные модификации и проблемы, которые это может вызвать.
Одна вещь, которую Java делает внутренне, заключается в том, что класс коллекции хранит счет того, сколько раз он обновлялся. И затем итератор проверяет это значение в каждом .next () по сравнению с тем, что было при создании интегратора, чтобы увидеть, обновлялась ли коллекция во время итерации. Я думаю, что этот принцип можно было бы использовать более широко.
Попробуйте ConTest или Скрытность
Оба инструмента анализируют код, чтобы выяснить, какие части данных могут быть разделены между потоками, а затем они обрабатывают код (добавляют дополнительный байт-код к скомпилированным классам), чтобы проверить, не сломался ли он, когда два потока пытаются изменить некоторые данные в в то же время. Затем эти два потока запускаются снова и снова, каждый раз начиная их с немного отличающимся временным смещением, чтобы получить множество возможных комбинаций шаблонов доступа.
Также проверьте этот вопрос: Модульное тестирование многопоточного приложения?
Возможно, вас заинтересует подход, о котором писал Питер Вентжер, который он называет Детектор параллелизма . Я не верю, что он все еще использовал его с открытым исходным кодом, но, поскольку он описывает это, основная идея состоит в том, чтобы использовать AOP для инструментирования кода, который вы заинтересованы в профилировании, и записывать, какой поток коснулся какого поля. После этого нужно вручную или автоматически проанализировать сгенерированные журналы. Р>
Если вы сможете определить классы, небезопасные для потоков, статический анализ сможет определить, когда-либо они "экранировали" стать видимым для нескольких потоков. Обычно программисты делают это в своих головах, но, очевидно, они склонны к ошибкам в этом отношении. Инструмент должен быть в состоянии использовать аналогичный подход.
Тем не менее, из описанного вами варианта использования это звучит так же просто, как запоминание потока и выполнение утверждений на нем, может быть достаточно для ваших нужд.
class Foo {
private final Thread owner = Thread.currentThread();
void x() {
assert Thread.currentThread() == owner;
/* Implement method. */
}
}
Ссылка на владельца все еще заполняется, даже когда утверждения отключены, поэтому она не является полностью "бесплатной". Я также не хотел бы загромождать многие из моих уроков этим образцом.
Thread.holdsLock (Object) также может быть полезен для вас.
В приведенном вами конкретном примере SwingLabs имеет некоторый вспомогательный код для обнаружения нарушений потока событий и зависаний. https://swinghelper.dev.java.net/
Некоторое время назад я работал с инструментами профилирования java JProbe. Один из их инструментов (threadalyzer?) Искал нарушения синхронизации потоков. Глядя на их веб-страницу, я не вижу инструмент с таким названием или совсем то, что я помню. Но вы можете посмотреть. http://www.quest.com/jprobe/performance-home.aspx р>
Вы можете использовать профилировщик Netbeans или JConsole , чтобы подробно проверить состояние потоков