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

Как определить, что ждет мой метод?

У меня есть метод в Java, который вызывает несколько других методов. Этот метод вызывается из нескольких потоков в фиксированном пуле потоков. Количество работников совпадает с количеством доступных процессоров (ядер).

public void query() {
    method1();
    method2();
}

Когда я просматриваю выполнение программы с помощью VisualVM, времена method1() и method2() очень короткие, но query() время очень длительное. Но метод не имеет другого кода, кроме двух вызовов. Там может быть синхронизация внутри method1() и method2(), но ничего не видно в коде, которым я управляю.

Когда я уменьшаю количество работников в пуле до 1, это время самопомощи почти исчезло. Как однопоточные, так и многопоточные времена выполнения всей программы практически одинаковы. Я думаю, это означает, что мой метод query() ждет чего-то.

Нет тупиков, исполнение отлично. Два метода method1() и method2() вызывают много других вещей, включая классы библиотек в обфускационных баночках, поэтому мне нелегко его отлаживать. Однако метод query() вызывается непосредственно из рабочих потоков, используя java.util.concurrent.ExecutorService.

4b9b3361

Ответ 1

Я нашел проблему в прокси-классе, который обертывал другой класс в пользовательский механизм блокировки.

Я продолжил создание серии Thread Dumps. Поскольку я использовал JVisualVM для профилирования, во время процесса я создал несколько нитей Dump. Ctrl+Break тоже работал так же, как kill -3 <pid>, упомянутый Synesso в его ответе.

Я использовал Thread Dump Analyzer, упомянутый в комментариях для их анализа. Я не знал, что искать первым, но благодаря связыванию объектов и мониторов в TDA я нашел что-то вроде этого:

"pool-9-thread-32" #304 prio=5 os_prio=0 tid=0x000000002a706800 nid=0x348c waiting for monitor entry [0x000000003f06e000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.example.MyClass.method1(MyClass.java:400)
    - waiting to lock <0x0000000680837b90> (a com.example.DifferentClass)
    at com.example.MyClass.query(MyClass.java:500)
    ... omitted ...
    at java.util.concurrent.FutureTask.run(FutureTask.java:270)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:618)
    at java.lang.Thread.run(Thread.java:745)

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

DifferentClass расширяет абстрактный MyClass, и есть вызов от method1() до DifferentClass, где объект DTO передается методу, который выполняет большую обработку, протоколирование и, наконец, сохранение в базе данных. Прокси-класс использовался во время создания одного из классов обработки базы данных.

Ответ 2

Выполните команду kill на уровне 3 против текущего процесса. Все потоки будут удалять трассировку стека по стандарту, и приложение будет продолжать работать.

kill -3 <pid>

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

Ответ 3

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

Ответ 4

Я предлагаю запустить программу, используя режим отладки в вашей среде IDE, и поставить точки останова рядом с тем, что может показаться проблемой. Затем сделайте шаг (например, F7 в Netbeans) в точке, где программа делает задержку. Вы можете полностью вмешаться в запутанный код, хотя вы, возможно, не сможете устранить проблему там. Однако вы узнаете, где находится задержка.