博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Swing中耗时任务需要另起新线程,这个新线程中更新GUI的操作仍需由EDT来做(转)...
阅读量:7106 次
发布时间:2019-06-28

本文共 2597 字,大约阅读时间需要 8 分钟。

最近调试程序时发现,点击某个界面时会出现卡死的情况,出现的频率还是比较频繁的。

再次出现卡死的情况后,利用jvisualvm查看线程的运行情况,dump操作之后发现线程间出现了死锁:

Found one Java-level deadlock:
=============================
"Thread-122":
  waiting to lock monitor 0x484052e4 (object 0x1af2bb08, a com.raisecom.ems.templet.client.panel.SnmpTablePanel),
  which is held by "AWT-EventQueue-0"
"AWT-EventQueue-0":
  waiting to lock monitor 0x4861c81c (object 0x180d5950, a java.awt.Component$AWTTreeLock),
  which is held by "Thread-122“

再在线程堆栈中查看根源的线程及方法,找到如下的代码:

public void onSelectionChanged(SelectionChangedEvent e) {  Object source = e.getSource();  if (source instanceof AbstractMenuTreePanel)  {   ///单起个线程处理显示   Thread thread = new Thread(){    public void run()    {      if(!"".equals(DemarcationConfigCenterView.this.m_ProVer))            refreshConfigPanel2();                 else         refreshConfigPanel();       }         }    }   };   thread.start();  }

EDT以外的线程中更新界面都需要SwingUtilities.invokeLater,修改代码:

public void onSelectionChanged(SelectionChangedEvent e) {  Object source = e.getSource();  if (source instanceof AbstractMenuTreePanel)  {   ///单起个线程处理显示   Thread thread = new Thread(){    public void run()    {      if(!"".equals(DemarcationConfigCenterView.this.m_ProVer))      SwingUtilities.invokeLater(new Runnable() {              public void run() {        refreshConfigPanel2();       }      });                  else{      SwingUtilities.invokeLater(new Runnable() {              public void run() {        refreshConfigPanel();       }      });           }    }   };   thread.start();  }

测试没有发生客户端卡死的现象了。

当swing界面程序启动的时候,会启动3个进程, 1、主线程 2、系统工具包线程:负责捕获操作系统事件,然后将事件转换成swing的事件,然后发送到事件派发线程EDT 3、事件派发线程(EDT):将事件派发到各个组件,并负责调用绘制方法更新界面

所有的事件,例如键盘,鼠标事件,都会由工具包线程转换成swing事件,然后放到事件队列EventQueue中,而这个EventQueue的派发机制是由EDT来管理的。 所以任何修改组件状态的方法都应该在EDT中执行,包括构造方法。Swing这样的构造原理经常会造成的情况就是,在EDT中执行长时间的事件,使EDT不能及时响应更新界面的事件,就是所说的界面卡住,这种不光是新手就是比较熟练的程序员也会犯的一个错误。所以必须避免在EDT中执行长时间的操作,而避免的方法就是多线程,启动另外的线程来处理冗长的操作,比如操作数据库,读写文件等,在这过程中可能要更新界面来给用户以提示,比如显示一个进度条,过一段事件更新一下界面,但是在EDT以外的线程中更新界面都是无效的,这在前面已经说过,要更新界面就要将对界面的更新操作放到EDT中,但是事件又是在另外的线程中执行的,要解决这个问题就要使用SwingUtilities提供的一个方法了 invokeLater, 

public void actionPerformed(ActionEvent e){    new Thread(new Runnable(){            //do something            SwingUtilities.invokeLater(new Runnable(){                pulic void run(){                    //update the GUI                }            });    }).start;}

 

这个方法的作用就是将一个更新界面的任务放到EDT中,EDT会在适当的时候进行调用以更新界面。invokeLater负责创建一个含有Runnable的特定事件,并让其在EDT中排队等待调用,当被调用时就会运行Runnable中的run方法进行派发。

http://www.cnblogs.com/lnlvinso/p/3685863.html

 

转载于:https://www.cnblogs.com/softidea/p/4672313.html

你可能感兴趣的文章
java反射--方法反射的基本操作
查看>>
协方差矩阵
查看>>
创建与合并分支【转】
查看>>
爬取本blog的所有标题和链接
查看>>
普通用户使用的命令-系统信息查看类命令
查看>>
【转】一次SpringMVC+ Mybatis 配置多数据源经历
查看>>
exception is the version of xbean.jar correct
查看>>
Hibernate demo之使用注解
查看>>
.NET Core 实现定时抓取博客园首页文章信息并发送到邮箱
查看>>
CSDN日报20170416 ——《为什么程序猿话少钱多死得早?》
查看>>
Retrofit网络框架入门使用
查看>>
Oracle-PLSQL提示“记录被另一个用户锁住”
查看>>
GetBulkRequest PDU的应用
查看>>
使用 JavaScript开发的跨平台音乐、书籍播放器
查看>>
[na]完全理解icmp协议
查看>>
高级语言基本特性
查看>>
Socket 与 WebSocket
查看>>
UWP x:bind
查看>>
GMT与Etc/GMT地区信息的时区转换
查看>>
66. Plus One
查看>>