Поток заблокирован в операторе println в Java
У нас запущено несколько экземпляров приложения (по одному на сервер tomcat) на одном физическом хосте. Приложение делает приличную регистрацию. Недавно мы заметили, что некоторые приложения работают медленнее или зависают и требуют перезапуска. В дампе потока обнаружено, что все потоки были заблокированы в операторе журнала, ожидая блокировки на println
объект. и какой-то другой объект уже заблокирован println
, Но я не мог понять, почему другой поток не снял блокировку на println
объект? Я вставил несколько снимков дампа потока:
ЗАБЛОКИРОВАНА Нить дампа:
java.lang.Thread.State: BLOCKED (on object monitor)
at java.io.PrintStream.println(PrintStream.java:755)
- waiting to lock <0x00000007830097e0> (a java.io.PrintStream)
at org.apache.tomcat.util.log.SystemLogHandler.println(SystemLogHandler.java:238)
at com.webaroo.smsnew.common.SMSUtils.log(SMSUtils.java:167)
at com.webaroo.smsnew.common.SMSUtils.log(SMSUtils.java:113)
Поток дампов потока, который взял журнал печати.
java.lang.Thread.State: BLOCKED (on object monitor)
at java.nio.CharBuffer.wrap(CharBuffer.java:350)
at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:246)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:106)
- locked <0x00000007830098f0> (a java.io.OutputStreamWriter)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:190)
at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:111)
- locked <0x00000007830098f0> (a java.io.OutputStreamWriter)
at java.io.PrintStream.write(PrintStream.java:476)
- locked <0x00000007830097e0> (a java.io.PrintStream)
at java.io.PrintStream.print(PrintStream.java:619)
at java.io.PrintStream.println(PrintStream.java:756)
- locked <0x00000007830097e0> (a java.io.PrintStream)
at org.apache.tomcat.util.log.SystemLogHandler.println(SystemLogHandler.java:238)
1 ответ
Обнаружено, что все потоки были заблокированы в операторе журнала, ожидая блокировки на объекте println. и другой объект уже заблокирован в println.
PrintStream
класс, который System.out
а также System.err
являются синхронизированными классами. любой println(...)
заблокируйте метод перед печатью, чтобы несколько потоков не перекрывали выходные строки.
То, что дамп потока показывает поток, заблокированный в этом месте, не означает, что он завис. Это просто означает, что это самая медленная часть вашего приложения. Другие дампы потоков покажут, что другие потоки делают это в println()
но и там заблокирован. Если там заблокировано несколько потоков, то вывод IO (возможно, на консоль) замедляет работу вашего приложения. Вы должны уменьшить количество методов журнала или уменьшить количество информации в каждом сообщении. Если это не поможет, вам придется рассмотреть другие механизмы вывода.
Если вам нужен вывод, то каждый поток может писать в свой BufferedWriter
обертывание FileWriter
например. Или вы можете сделать так, чтобы один поток выполнял фактический вывод, а все остальные потоки добавляли свои сообщения в BlockingQueue
и один писатель выдает сообщение в очередь, а затем записывает его в BufferedWriter
который не блокирует и буферизует свой ввод / вывод.
private final BlockingQueue<String> messageQueue
= new ArrayBlockingQueue<String>();
...
// add a message to the queue
messageQueue.add("some log output here: " + someValue);
...
// writer thread
private class LogThread implements Runnable {
public void run() {
BufferedWriter writer =
new BufferedWriter(new FileWriter("/var/log/some_log_file.txt"));
try {
while (!Thread.currentThread().isInterrupted()) {
String msg = messageQueue.take();
writer.write(msg);
}
} finally {
writer.close();
}
}
}
Однако вы можете обнаружить, что даже если у вас есть один поток, записывающий через буферизованный поток, что вы превышаете пропускную способность ввода-вывода вашего жесткого диска. Вы можете попробовать gziped поток в этот момент, но обычно переоценка результатов в порядке. Можете ли вы уменьшить количество выходных линий? Можете ли вы сохранить какие-то счетчики в памяти и делать это время от времени. Если вам действительно нужен вывод журнала, вам, возможно, придется подумать об увеличении скорости вашего диска путем перехода на SSD.