Swing中耗时任务需要另起新线程,这个新线程中更新GUI的操作仍需由EDT来做(转)

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

再次出现卡死的情况后,利用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

 

时间: 2024-12-30 23:45:19

Swing中耗时任务需要另起新线程,这个新线程中更新GUI的操作仍需由EDT来做(转)的相关文章

新北冰洋汽水下周上市每瓶售价2.5元仍需“退瓶”

和北京人久别了15年的北冰洋汽水,将于本周和消费者"重逢".北冰洋有关负责人昨天透露,由于玻璃瓶包装给运输和零售带来一定限制,首批上市的汽水将在义利食品店和大街上的冷饮屋.街边店同步上市.产品的规格为248毫升的小玻璃瓶装,每瓶售价2.5元.和15年前一样,消费者喝完汽水可还得想着"退瓶". 从北冰洋的新包装来看,苗条的玻璃瓶身配上经典的皇冠形金属盖,瓶身上印制的"大白熊"依然憨态可掬.按照北冰洋的计划,今年7月初生产设备到货,9月安装准备完毕,

博奥新能求救:html中的DIV嵌套一个DIV,怎么让里面的DIV剧中?

问题描述 博奥新能求救:html中的DIV嵌套一个DIV,怎么让里面的DIV剧中? 博奥新能在写代码的时候发现这个问题一直没办法解决,IE和360都不能,所以博奥新能不知道哪里出了问题,请大神帮忙解决一下.谢谢.. 解决方案 div剧中css代码div上下左右剧中 解决方案二: 可以尝试一下: 1.对需要水平居中的DIV层添加以下属性: margin-left: auto; margin-right: auto; 2.主要的样式定义如下: body {TEXT-ALIGN: center;} #

Javascript中prototype属性实现给内置对象添加新的方法

  本文实例讲述了Javascript中prototype属性实现给内置对象添加新的方法.分享给大家供大家参考.具体实现方法如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" con

新浪UC群组中上传图片支持哪些格式

目前在新浪UC群组中上传图片,支持jpg.gif.bmp.png这4种格式. 简介 UC(Universal Communication)是新浪UC信息技术有限公司开发的,融合了P2P思想的下一代开放式即时通讯的网络聊天工具. 新浪UC2009II正式版是新浪在2009年9月27日最新发布的版本.新版UC改变了老UC只是一个视频聊天软件的形象,趋向于打造为实用性与便捷性并重的多功能聊天软件,在IM的发展历程上树立了一个划时代的里程碑.突破性地增加了远程演示.IM互通.500人免费群组.超大文件传

Linux中利用两个现存文件,生成一个新的文件

Linux中利用两个现存文件,生成一个新的文件的方法 前提条件:每个文件中不得有重复行 1. 取出两个文件的并集(重复的行只保留一份) cat file1 file2 | sort | uniq 2. 取出两个文件的交集(只留下同时存在于两个文件中的文件) cat file1 file2 | sort | uniq -d 3. 删除交集,留下其他的行 cat file1 file2 | sort | uniq –u

timer的用法-javax.swing.Timer中的线程是不是守护线程,盼大神指点

问题描述 javax.swing.Timer中的线程是不是守护线程,盼大神指点 这是源代码 import java.awt.*; import java.awt.event.*; import javax.swing.*; class mytime implements ActionListener { Timer time; int n=0; mytime() { time=new Timer(1000,this); time.start(); } public void actionPerf

ios开发中怎样实现点击按钮之后打开一个新的webview ?

问题描述 ios开发中怎样实现点击按钮之后打开一个新的webview ? 我自己做的登录验证页面,验证那一部分做完了,我想要点击按钮之后直接跳转到一个网页,这中间的具体步骤该如何实现?我需要在故事板中构造一个界面来存放webview吗. 解决方案 可以用代码实现,也可以用StoryBoard实现. 图一: 1.在StoryBoard中新建一个ViewController,在文件中新建一个Cocoa Touch Class,将Cocoa Touch Class绑定到ViewController上,

MySQL · 新特性分析 · 5.7中Derived table变形记

Derived table实际上是一种特殊的subquery,它位于SQL语句中FROM子句里面,可以看做是一个单独的表.MySQL5.7之前的处理都是对Derived table进行Materialize,生成一个临时表保存Derived table的结果,然后利用临时表来协助完成其他父查询的操作,比如JOIN等操作.MySQL5.7中对Derived table做了一个新特性.该特性允许将符合条件的Derived table中的子表与父查询的表合并进行直接JOIN.下面我们看一下DBT-3中

java-新手求助:sql语句,从多个表中取出最新时间的记录,组成一个新表

问题描述 新手求助:sql语句,从多个表中取出最新时间的记录,组成一个新表 解决方案 mysql的实现: insert into zongbiao(id, name ,vd,co2,wendu,time) select t1.id,t1.name,t1.vd,t2.co2,t2.wendu,t2.time from biao1 t1 join biao2 t2 on(t1.id=t2.id) order by t2.time desc limit 1; 解决方案二: 1.mysql和oracle