Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中println语句上的线程阻塞_Java_Multithreading_Thread Dump_Blocked Threads - Fatal编程技术网

Java中println语句上的线程阻塞

Java中println语句上的线程阻塞,java,multithreading,thread-dump,blocked-threads,Java,Multithreading,Thread Dump,Blocked Threads,我们在单个物理主机上运行多个应用程序实例(每个tomcat服务器一个)。 应用程序可以进行适当的日志记录。 最近,我们发现一些应用程序速度变慢或挂起,需要重新启动。 在线程转储中,发现所有线程都被日志语句阻塞,等待锁定println对象。而另一个对象已经锁定了println。 但我不明白为什么其他线程没有释放println对象上的锁? 我正在粘贴一些线程转储快照: 阻塞线程转储: java.lang.Thread.State: BLOCKED (on object monitor) at

我们在单个物理主机上运行多个应用程序实例(每个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:已阻止(在对象监视器上)
在java.io.PrintStream.println(PrintStream.java:755)
-等待锁定(java.io.PrintStream)
位于org.apache.tomcat.util.log.SystemLogHandler.println(SystemLogHandler.java:238)
位于com.webaroo.smsnew.common.SMSUtils.log(SMSUtils.java:167)
位于com.webaroo.smsnew.common.SMSUtils.log(SMSUtils.java:113)
获取println日志的线程的线程转储

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)
java.lang.Thread.State:已阻止(在对象监视器上)
位于java.nio.CharBuffer.wrap(CharBuffer.java:350)
在sun.nio.cs.streamncoder.implWrite上(streamncoder.java:246)
在sun.nio.cs.streamncoder.write中(streamncoder.java:106)
-锁定(java.io.OutputStreamWriter)
在java.io.OutputStreamWriter.write(OutputStreamWriter.java:190)中
位于java.io.BufferedWriter.flushBuffer(BufferedWriter.java:111)
-锁定(java.io.OutputStreamWriter)
在java.io.PrintStream.write处(PrintStream.java:476)
-锁定(一个java.io.PrintStream)
在java.io.PrintStream.print(PrintStream.java:619)
在java.io.PrintStream.println(PrintStream.java:756)
-锁定(一个java.io.PrintStream)
位于org.apache.tomcat.util.log.SystemLogHandler.println(SystemLogHandler.java:238)
发现所有线程在log语句上都被阻塞,等待对println对象的锁定。而另一个对象已经锁定了println

PrintStream
类,即
System.out
System.err
,都是同步类。任何
println(…)
方法在执行打印之前都会锁定,以便多个线程不会获得重叠的输出行

线程转储显示在该位置阻塞的线程并不意味着它已挂起。这可能只是意味着它是应用程序中最慢的部分。更多的线程转储将显示其他线程正在进入
println()
,但也在那里被阻塞。如果有许多线程在那里被阻塞,那么输出IO(可能到控制台)就是减慢应用程序的原因。您应该减少日志方法的数量或减少每条消息中的信息量。如果这无济于事,那么你将不得不考虑其他的输出机制。 如果您需要输出,那么每个线程都可以写入自己的
BufferedWriter
,例如包装一个
FileWriter
。或者,您可以让一个线程执行实际输出,所有其他线程将其消息添加到
阻塞队列
,一个编写器将消息退出队列,然后将其写入不锁定和缓冲其I/O的
缓冲编写器

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();
       }
    }
}
private final BlockingQueue messageQueue
=新的ArrayBlockingQueue();
...
//将消息添加到队列中
add(“此处的一些日志输出:”+someValue);
...
//写线程
私有类LogThread实现可运行{
公开募捐{
缓冲写入程序=
新的BufferedWriter(新的FileWriter(“/var/log/some_log_file.txt”);
试一试{
而(!Thread.currentThread().isInterrupted()){
字符串msg=messageQueue.take();
writer.write(msg);
}
}最后{
writer.close();
}
}
}

但是,您可能会发现,即使有一个线程通过缓冲流写入,也超出了硬盘的IO带宽。您可以在该点尝试gziped流,但通常需要重新评估输出。你能减少输出线的数量吗?你能在内存中保留一些计数器并经常转储吗。如果您真的需要日志输出,那么您可能需要考虑通过移动到SSD来增加驱动器的速度。

谢谢,我从线程转储中添加了一个丢失的日志:“THEAD-71Daimon PrIO=10 TID= 0x09007F367C0D0000 NID= 0x3A9B等待监视器条目[0x09007F35D83C000 ] java. Lang.thRead状态:阻止(在对象监视器上)在java.nio.CharBuffer.wrap(CharBuffer.java:350)中,上面的锁未被释放的原因是什么?以及任何其他可用于更高日志应用程序的异步日志框架?@Pramod您没有证据表明锁没有被释放。做几个快照,每次你都会看到一个不同的线程持有锁。你只是有很高的锁争用率,仅此而已。Marko是对的@Pramod。快照在该位置显示线程并不意味着它挂起。这只是意味着它是应用程序中最慢的部分。更多的线程转储将显示其他线程正在进入
println()
,但也在那里被阻塞。你能减少邮件的大小或数量吗?您可以尝试log4j或其他日志包。但是,您可能会发现,您刚刚超出了驱动器的IO带宽。您可能需要移动到SSD。@Gray,在应用程序挂起/停止大约1小时后,我进行了线程转储。并且应用程序正在tomcat服务器中运行,因此日志将在log/catalina.out文件中可用。您如何知道它没有释放锁,而只是将锁保持足够长的时间,以便您在快照中看到它?我会尽可能少地登录到屏幕上。理想情况下什么都没有。将所有内容写入文件。lo