最近调试程序时发现,点击某个界面时会出现卡死的情况,出现的频率还是比较频繁的。
再次出现卡死的情况后,利用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来管理的。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