java - 如何在多线程应用程序关闭时摆脱有关 "no appenders"的 log4j 消息警告?

标签 java multithreading log4j application-shutdown

我有一个多线程程序,它基本上有两个无限循环线程加上一些 GUI (Swing)。我的两个无限循环线程有自己的 log4j 记录器,如下所示:

    static final Category LOG = Category.getInstance(RReceiver.class);

当在 GUI 中检测到退出键时,我只需执行 System.exit(0):

public boolean dispatchKeyEvent(KeyEvent e) {
    if (e.getKeyCode()!=27 && e.getKeyCode()!=KeyEvent.VK_BACK_SPACE) return false; 
    System.exit(0);
    return true;
}

控制台中的效果是这样的:

DEBUG 13:07:00,940 [ Receiver] (RReceiver.java:93) - got response len:38
DEBUG 13:07:01,044 [ Receiver] (RReceiver.java:93) - got response len:38
DEBUG 13:07:01,045 [ Receiver] (RReceiver.java:93) - new status dev 4
log4j:WARN No appenders could be found for logger (com.normantech.ibcol.radiobox.RReceiver).
log4j:WARN Please initialize the log4j system properly.

警告并不总是出现。我怀疑去初始化序列有错误,但无法弄清楚。 为什么会发生这种情况?我尝试使用 LogManager.shutdown();但这没有帮助。我试图很好地完成我的无限循环,但这不是最好的解决方案,因为我需要添加一些额外的 Thread.sleep(x),尝试不同的 x,实际上不确定这是否有帮助。

最佳答案

核心问题是您通过调用 System.exit() 来终止线程,而不是让它们干净地关闭。这意味着它们可能会在其他所有内容关闭之后但在 JVM 实际结束进程之前继续运行很短的时间,并且如果它们在此期间使用任何共享状态(例如日志系统),则它可能处于不一致或损坏的状态,因为它可能已被关闭。这不是一个好的做法(请参阅 http://www.javapractices.com/topic/TopicAction.do?Id=86 )。

解决这个问题的方法是在关闭共享资源(日志系统)之前正确关闭线程。不要只调用 system.exit(),而是告诉每个线程该停止了,并等待它们这样做。最简洁的方法是让他们在每个循环上检查正在运行的 boolean 值,并在您希望循环停止时从外部将该 boolean 值设置为 false。然后,您可以等待线程注意到此 boolean 值并通过在给定线程实例上调用 Thread.join() 来终止,或者让线程在完成时设置一些 finished boolean 值(最好将两者都标记为这些 boolean 值是 volatile 的)。

如果循环的每次迭代都需要一些时间,或者包含 wait()sleep() 调用,您应该在循环期间更频繁地检查正在运行的 boolean 值,或使用 Thread.interrupt()。

一旦完成并且您确定其他所有线程都已停止,您就可以调用 LogManager.shutdown() 并实际终止您的进程。

关于java - 如何在多线程应用程序关闭时摆脱有关 "no appenders"的 log4j 消息警告?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16168304/

相关文章:

java - ClassCastException : org. apache.xerces.jaxp.DocumentBuilderFactoryImpl 无法转换为 javax.xml.parsers.DocumentBuilderFactory

java - 程序每次都给出相同的结果,而它应该是随机的

x86 架构上的 Java、volatile 和内存屏障

java - log4j 级别 DEBUG 是否包含 ERROR?

java - 将图像文件从 RGB 转换为 YUV 的有效方法

java - Wicket 快速双击提交按钮

java - 线程池中要创建多少个线程

objective-c - Objective-C中如何在指定时间唤醒线程

java - 是否可以使用 Log4j 为自定义输出创建单独的日志输出文件

java - 在 Tomcat 中作为 WAR 运行的 Grails 项目中 Maven-build JAR 的 SLF4J 配置位置