在swing系统中,有一个顶级的java.awt.Container(可能是一个JFrame或JDialog实例),负责启动一个EventDispatchThread的线程,单线程,这个线程是负责处理UI事件的,如点击按钮、窗口关闭等
因此,如果将繁琐耗时的处理逻辑放到actionPerformed之类的事件处理方法中,那么这些代码是由EDT来执行的,而EDT负责处理UI事件,则会引起UI失去响应。
此时,可以将处理逻辑放到一个新的线程中来执行,这样就不会影响EDT去处理UI事件,就不会“卡死”。但假如此逻辑需要更新UI,由于swing不是线程安全的,该线程直接修改可能会导致线程安全问题(该线程和EDT可能同时进行修改)
解决办法:
javax.swing.SwingUtilities的invokeLater和invokeAndWait方法就是用于解决此问题的,我们将更新UI的代码放到一个Runnable中,作为参数传给invokeLater或invokeAndWait,由它扔回给EDT来执行(其实是放到EDT维护的一个队列中,EDT会在合适的时候从队列中取出该Runnable,执行其run方法),这样一来,仍然是EDT在更新UI,所以不会出现线程安全问题,invokeLater和invokeAndWait的区别在于invokeAndWait会阻塞调用该方法的线程,直到对应的run执行完毕返回(由于会阻塞当前线程,故不能在EDT中调用该方法,在java1.6中,会检测当前线程是不是EDT,是则会抛出一个Error),而前者直接返回
PS:虽然网上有不少这方面的资料,但我看了很多都没明白invokeLater和invokeAndWait的适用场景是什么,只知道它干了点啥,被绕来绕去后才琢磨明白其原由,希望此文能解决某些人的疑惑。
没有进行仔细论证,只是觉得全部打通了,自以为找到了其原由,若有错误之处,还请高人指正!
补充:关于该问题有个更好的解决办法是使用SwingWorker