</div> </div>
JButton button = new JButton(); button.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent e) { //位置A SwingUtilities.invokeLater(new Runnable() { public void run() { //位置B invokeRemoteService();//可能需要等待 } }); doOtherThing(); } });
这段代码跟第一段代码唯一的差别是doOtherThing()在invokeRemoteService ()完成之前就能够得到执行,所以造成了invokeRemoteService ()/doOtherThing()好像是在两个线程里执行的假象。
实际上invokeLater是把目标代码打包成一个Event提交到EventQueue去了,等到EventDispatchThread线程执行完当前代码段的doOtherThing()后,
再去执行这个EventQueue中的Event,这时候就会执行到这个invokeRemoteService ()方法。
但是,实际上这两个方法都是在EventDispatchThread中执行的,并没有任何其他Thread来执行。
于是,问题1的问题还是没解决。实际上直接new Thread().start()方法就可以了,使用SwingUtilities完全是由于误解造成的滥用。
测试方法,在位置A和位置B都加上下面这行代码:
System.out.println(Thread.currentThread().getId() + Thread.currentThread().getName());
返回的结果都是一样的:
21AWT-EventQueue-0
21AWT-EventQueue-0 [讨论]
一般情况下(除了系统启动时后台创建的Daemon线程),系统的所有执行功能逻辑和业务逻辑的线程都应该是从界面操作触发的。
我们应该清楚哪些需要或应该放到EventDispatchThread中去执行,哪些需要或应该创建一个新线程去执行,也需要清醒的知道自己当前编写的是属于什么逻辑。
这个问题我觉得应该把代码分成3层,第一层,UI层,包括UI控件上的Listener逻辑,这是应该给EventDispatchThread去执行的,必须简短高效,快速return;
这一层做不完的事情通过new Thread().start()交给下一层去做,我称之为控制层;然后控制层再去调用具体的业务代码,即第三层,业务层。所有由UI控件触发的逻辑都应该这么分。
另一个问题是,Swing并不推荐在EventDispatchThread之外修改界面,那么,如果我们在业务层需要repaint某个控件,
或者updateUI应该怎么办呢,那就可以使用SwingUtilities来处理了,这才是正确使用SwingUtilities的场景,也是设计这个工具的目的。