swing程序的关闭机制--看好你的swing.Timer,别让它成为程序不能退出的原凶

时间:2021-09-24 03:16:15

  java中常见的Timer有两个,一个是javax.swing.Timer,另一个是java.utl.Timer,两者的功能大同小异,最主要的差别在于swing.Timer的任务是放到EDT线程中执行的,可以很方便地进行swing的UI操作,另外swing.Timer是一个守护线程,utl.Timer则是可以设置是否为守护线程。

  JVM中有这样一个规定,如果非守护线程都退出了,那么JVM会关闭,不管是否还有守护线程在运行。

  swing程序的关闭机制:在swing程序中,EDT线程负责处理事件,它是一个非守护线程;另外有一个名为AWT-Shutdown的非守护线程,负责在所有窗口都关闭后,关闭EDT线程,然后自己退出,所以正常情况下,窗口都关闭时,程序是会自动退出的(不是调用System.exit)。

  前不久在项目中碰到个问题,我使用了一个循环执行的Timer后(以下均指javax.swing.Timer),窗口全关闭后程序也不退出了(窗口全关闭后,如果再没有非守护线程,虚拟机应该是会自动退出的),后来我把timer的周期改为了1000+毫秒,程序就能退出了,小于1000就无法退出。之后经过调试跟踪,了解了swing的关闭机制,而且注意到,在窗口都关闭时,AWT-Shutdown它并不是立即关闭EDT线程,而是mainLock.wait1000毫秒,然后再次检查关闭条件(还会检查EDT中是否有任务正在执行),如果不符合,就继续寻找关闭的时机,循环此过程,所以,如果timer的间隔小于1000,主意味着,AWT-Shutdown在waait的1000毫秒中,又有新的任务被放到EDT任务队列中,当AWT-Shutdown醒来时,关闭条件又不符合了,所以,如果你的timer间隔小于1000,将造成AWT-Shutdown不能关闭EDT,程序无法退出,说到这里,可能大家也明白了,并不只是timer,使用SwingUtilities.invokeAndWait、invokeLater、SwingWorker等,都会有此问题。

  有兴趣的朋友可以阅读下AWTAutoShutdown的源码,那些细节挺有意思的。