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



我有一个多线程程序,基本上有两个无限循环线程加上一些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) - get response len:38
DEBUG 13:07:01,045 [Receiver] (RReceiver.java:93) -新状态dev 4
log4j:警告无法找到记录器(com.normantech.ibcol.radiobox.RReceiver)的appeners。
log4j:WARN请正确初始化log4j系统。

警告并不总是出现。我怀疑有错误的反初始化顺序,但不能弄清楚。为什么会这样呢?我已经尝试使用LogManager.shutdown();但这无济于事。我试图很好地完成我的无限循环,但这不是最好的解决方案,因为我需要添加一些额外的Thread.sleep(x),尝试不同的x,并且实际上不确定这是否有帮助。

核心问题是调用System.exit()会杀死线程,而不是让它们干净利落地关闭。这意味着它们可能会在其他所有东西关闭之后,但在JVM实际结束进程之前短暂地运行,如果它们在此期间使用任何共享状态(例如日志系统),那么它可能处于不一致或损坏状态,因为它可能已经关闭。这不是一个好的做法(参见http://www.javapractices.com/topic/TopicAction.do?Id=86)。

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

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

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

相关内容

最新更新