Где искать синхронизированные доказательства конкуренции в Java? - PullRequest
3 голосов
/ 08 августа 2009

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

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

Как я могу точно знать, является ли конфликт потоков в моем приложении?

Ответы [ 6 ]

7 голосов
/ 08 августа 2009

Я думаю, что подробности потока представление инструмента visualVM, который поставляется с последними JDK Java 6, сможет предоставить убедительные доказательства (или против) вашей теории. Он отображает круговую диаграмму для каждого потока, показывая, сколько времени он тратит на бег, сон, ожидание и на мониторе. Последнее (отображается красным цветом) - это то, что вас интересует:

alt text

3 голосов
/ 08 августа 2009

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

1 голос
/ 08 августа 2009
jstack PID

распечатает список состояний JVM с идентификатором процесса PID, а также информацию о статусах потоков.

пример выходных данных (отрывок):

"AWT-XAWT" daemon prio=10 tid=0x0000000000e5f800 nid=0x476d runnable [0x00007f1a75616000..0x00007f1a75616bf0]
   java.lang.Thread.State: RUNNABLE
    at sun.awt.X11.XToolkit.waitForEvents(Native Method)
    at sun.awt.X11.XToolkit.run(XToolkit.java:543)
    at sun.awt.X11.XToolkit.run(XToolkit.java:518)
    at java.lang.Thread.run(Thread.java:636)

"Java2D Disposer" daemon prio=10 tid=0x0000000000d8b800 nid=0x476c in Object.wait() [0x00007f1a759df000..0x00007f1a759dfc70]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00007f1a82e2c3f8> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:133)
    - locked <0x00007f1a82e2c3f8> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:149)
    at sun.java2d.Disposer.run(Disposer.java:143)
    at java.lang.Thread.run(Thread.java:636)

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

1 голос
/ 08 августа 2009

В вашем распоряжении есть java профилировщики с открытым исходным кодом , а также другие, которые могут стоить денег, например YourKit . Вы должны запускать тесты как с существующим кодом, так и с вашим расширенным кодом. Работа с ThreadLocals в целом должна снизить конкуренцию, но учтите, что перед началом оптимизации также полезно провести сравнительный анализ.

Еще один довольно простой тест, который можно выполнить без настройки какого-либо профилировщика, - это сделать несколько дампов потоков (ctrl-break или kill -QUIT), пока приложение работает медленно. Обнаружение нескольких потоков, ожидающих на одинаковых или одинаковых мониторах в течение короткого промежутка времени, может довольно четко указать на медленные точки. Вы можете использовать инструменты, такие как TDA , анализатор дампа потока Java, чтобы помочь вам прочесать дамп потока.

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

0 голосов
/ 08 августа 2009

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

0 голосов
/ 08 августа 2009

Я мог бы добавить запись в наших синхронизированных звонках, как это

//...
long t0 = System.currentTimeMillis();
synchronized(lockObj){
    logger.info("T sync :" + (t0 - System.currentTimeMillis()));
    //...
}

но это кажется дешевым и грязным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...