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

再次出现卡死的情况后,利用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方法进行派发。

最新文章

  1. opencv,图片遍历
  2. ubantu14下vim的配置...
  3. 【PRML读书笔记-Chapter1-Introduction】1.3 Model Selection
  4. jquery点击控制动画暂停开始
  5. poj 2431 Expedition
  6. Webstorm10.0.4注册码
  7. Hibernate4.x之映射文件
  8. Android TextView属性
  9. java ClassLoader static
  10. SpringMvc文件资源防止被外链链接
  11. 兄弟连学Python-3Python变量和数据类型
  12. Django 后台定制自己的选择框删除函数
  13. 论文阅读笔记四十五:Region Proposal by Guided Anchoring(CVPR2019)
  14. Linux 防火墙管理及操作
  15. 闭包,jQuery插件的写法:图片预加载
  16. Android Studio 解决ADB检测不到手机导致无法连接的问题
  17. [Spark][Hive][Python][SQL]Spark 读取Hive表的小例子
  18. day 21 封装,多态,类的其他属性
  19. goconfig - INI 解析器
  20. mysql root更改远程登录

热门文章

  1. c++工程重复编译与重复定义
  2. cesium编程入门(四)界面介绍及小控件隐藏
  3. JavaScript变量声明与提升
  4. TCP协议中三次握手
  5. ArcGIS中实现指定面积蜂窝(正六边形)方法
  6. DOM解析原理示意
  7. 最近公司用到了lombok,感觉很不错的样子,所以上网搜了一些资料,总结了一下用法。
  8. CentOS 7安装Oracle 11gR2以及设置自启动
  9. [one day one question] webpack打包压缩 ES6 js、.vue报错
  10. Go_Hello word