编码Swing多线程的过程中有什么误区
创始人
2024-12-19 00:22:19
0次

  1、不要以为Swing是多线程的,实际上Swing的UI是单线程的

  2、不要以为SwingUtilities.的两个invoke是多线程,实际上它还是单线程的

  3、不要以为invokeLater的意思是当前线程执行完再执行目标线程;以为invokeAndWait的意思是等待目标线程执行完再执行当前线程,实际上压根就不是那么回事

  问题代码1:大意是在按下某个按钮的时候调用一个远程服务

  1.JButtonbutton=newJButton();

  2.button.addActionListener(newActionListener(){

  3.@Override

  4.publicvoidactionPerformed(ActionEvente){

  5.invokeRemoteService();//可能需要等待

  6.}

  7.});

  在swing系统中,有一个顶级的java.awt.Container(可能是一个JFrame或JDialog实例),负责启动一个EventDispatchThread线程,单线程,这个线程是负责处理UI事件的。

  首先,界面Swing控件向EventDispatchThread的EventQueue提交一个event,由EventDispatchThread负责调度各个event的执行。例如,按下一个JButton的时候,JButton向EventQueue执行postEvent,提交一个ActionEvent.EventDispatchThread线程根据调度算法执行到该event的时候,会调用JButton上的processActionEvent,JButton再调用actionPerformed,这过程并没有执行任何newThread()。start()代码,也就是说JButton的ActionListener.actionPerformed()中的代码完全是在EventDispatchThread线程内执行的。

  所以,假如我们在任何ActionListener、MouseListener等对象中编写耗时的逻辑,那么整个Swing系统就会出现响应迟钝的现象,更有甚者,如果在这些Listener中执行线程wait(),以等待另一个线程的锁定资源或计算结果,那么实际上就是EventDispatchThread线程被阻塞,整个系统界面就会处于无响应状态,一点反应都没有。

  以上是误解1造成的,了解这个过程,就很容易看出上面这段代码的问题是什么原因了。解决的方法也倒比较简单,直接newThread()。start();就可以保证EventDispatchThread执行到当前方法的时候快速返回,以便可以去响应来自用户界面的其他事件。

  Swing多线程编码过程中的误区有哪些

  问题代码2:大意是在按下某个按钮的时候调用一个远程服务,同时处理其他事情

  1.JButtonbutton=newJButton();

  2.button.addActionListener(newActionListener(){

  3.@Override

  4.publicvoidactionPerformed(ActionEvente){

  5.//位置A

  6.SwingUtilities.invokeLater(newRunnable(){

  7.publicvoidrun(){

  8.//位置B

  9.invokeRemoteService();//可能需要等待

  10.}

  11.});

  12.doOtherThing();

  13.}

  14.});

  这段代码跟第一段代码唯一的差别是doOtherThing()在invokeRemoteService()完成之前就能够得到执行,所以造成了invokeRemoteService()/doOtherThing()好像是在两个线程里执行的假象。实际上invokeLater是把目标代码打包成一个Event提交到EventQueue去了,等到EventDispatchThread线程执行完当前代码段的doOtherThing()后,再去执行这个EventQueue中的Event,这时候就会执行到这个invokeRemoteService()方法。但是,实际上这两个方法都是在EventDispatchThread中执行的,并没有任何其他Thread来执行。于是,问题1的问题还是没解决。实际上直接newThread()。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;这一层做不完的事情通过newThread()。start()交给下一层去做,我称之为控制层;然后控制层再去调用具体的业务代码,即第三层,业务层。所有由UI控件触发的逻辑都应该这么分。

  另一个问题是,Swing并不推荐在EventDispatchThread之外修改界面,那么,如果我们在业务层需要repaint某个控件,或者updateUI应该怎么办呢,那就可以使用SwingUtilities来处理了,这才是正确使用SwingUtilities的场景,也是设计这个工具的目的。

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...