单例log4j死锁
文章内索引
[显示]
静态单例模式下log4j死锁
问题描述:
排查以往项目中一个“卡住”的程序发现了如下问题,此项目结构如图。
nettyserver负责从client接收消息,并根据ID启动相应进程。进程并行处理消息时会偶然发生卡住的现象。
通过jstack排查发现由于log4j为单实例,并且多进程访问log4j写入日志会导致阻塞。发生阻塞的关键线程栈信息如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
"Thread-3" prio=10 tid=0x00007f3f04434800 nid=0x105d runnable [0x00007f3f00dec000] java.lang.Thread.State: RUNNABLE at java.io.FileOutputStream.writeBytes(Native Method) at java.io.FileOutputStream.write(FileOutputStream.java:345) at java.io.BufferedOutputStream.write(BufferedOutputStream.java:122) - locked <0x00000000d1af01a8> (a java.io.BufferedOutputStream) at java.io.PrintStream.write(PrintStream.java:480) - locked <0x00000000d1adac90> (a java.io.PrintStream) at org.apache.logging.log4j.core.appender.ConsoleAppender$CloseShieldOutputStream.write(ConsoleAppender.java:312) at org.apache.logging.log4j.core.appender.OutputStreamManager.write(OutputStreamManager.java:123) - locked <0x00000000d1b2c6a0> (a org.apache.logging.log4j.core.appender.OutputStreamManager) at org.apache.logging.log4j.core.appender.OutputStreamManager.write(OutputStreamManager.java:136) at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:110) at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:148) at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:121) at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:112) at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:80) at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:390) at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:378) at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:362) at org.apache.logging.log4j.core.config.LoggerConfig.logParent(LoggerConfig.java:384) at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:379) at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:362) at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:352) at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:59) at org.apache.logging.log4j.core.Logger.logMessage(Logger.java:138) at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:999) at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:954) at org.apache.logging.log4j.spi.AbstractLogger.info(AbstractLogger.java:669) at com.*.base.log.Log4j.info(Log4j.java:57) at com.*.TMENUS.GetTUListForMoreChunk(TMENUS.java:1615) Locked ownable synchronizers: - None |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
"main" prio=10 tid=0x00007f3f04008800 nid=0x1051 waiting for monitor entry [0x00007f3f0a2d9000] java.lang.Thread.State: BLOCKED (on object monitor) at org.apache.logging.log4j.core.appender.OutputStreamManager.write(OutputStreamManager.java:123) - waiting to lock <0x00000000d1b2c6a0> (a org.apache.logging.log4j.core.appender.OutputStreamManager) at org.apache.logging.log4j.core.appender.OutputStreamManager.write(OutputStreamManager.java:136) at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:110) at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:148) at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:121) at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:112) at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:80) at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:390) at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:378) at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:362) at org.apache.logging.log4j.core.config.LoggerConfig.logParent(LoggerConfig.java:384) at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:379) at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:362) at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:352) at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:59) at org.apache.logging.log4j.core.Logger.logMessage(Logger.java:138) at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:999) at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:954) at org.apache.logging.log4j.spi.AbstractLogger.info(AbstractLogger.java:669) at com.*.base.log.Log4j.log(Log4j.java:22) at com.handler.AnalysisHandler.Run(AnalysisHandler.java:275) |
main线程为主要的消息监听线程,thread-3线程为处理业务逻辑线程,它等待thread-3线程持有的OutputStreamManager对象时造成了阻塞。并未继续下发任务,导致程序卡住。
解决办法:
将log4j对象改为非单例模式,每个class持有一个log4j对象。或非关键进程降低日志级别,生产环境调高日志级别。
©版权声明:本文为【翰林小院】(huhanlin.com)原创文章,转载时请注明出处!
发表评论