• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
Xtrann's Fun loving Journing
博客园    首页    新随笔    联系   管理    订阅  订阅

深入浅出Java多线程(2)-Swing中的EDT(事件分发线程)

看到了吧,我们写的那个getFileLock 是由AWT-EventQueue-0  线程执行,看右下角调用关系, EventDispathThread 启动 Run方法, 然后pumpEvents 取事件,然后从EventQueue取到InvocationEvent 执行Dispath Dispath调用的就是我们在getFileLock写的run() 方法, JDK代码如下:
  public void dispatch() {
    
if (catchExceptions) {
        
try {
        runnable.run();
        } 
        
catch (Throwable t) {
                
if (t instanceof Exception) {
                    exception 
= (Exception) t;
                }
                throwable 
= t;
        }
    }
    
else {
        runnable.run();
    }

    
if (notifier != null) {
        
synchronized (notifier) {
        notifier.notifyAll();
        }
    }
    }
    runnable.run();而如何将我们写的getFileLock加入的那个EventQueue中的呢?当然是SwingUtilities.invokeAndWait(new getFileLock());看JDK代码:
 public static void invokeAndWait(Runnable runnable)
             
throws InterruptedException, InvocationTargetException {

        
if (EventQueue.isDispatchThread()) {
            
throw new Error("Cannot call invokeAndWait from the event dispatcher thread");
        }

    
class AWTInvocationLock {}
        Object lock 
= new AWTInvocationLock();

        InvocationEvent event 
= 
            
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock,
                
true);

        
synchronized (lock) {
           
Toolkit.getEventQueue().postEvent(event);
            lock.wait();
        }

    Toolkit.getEventQueue()。postEvent(event);把我们写的getFileLock 塞进了EventQueue.这下读者对EDT有个认识了吧。

    1. EDT 只有一个线程, 虽然getFileLock是实现Runnable接口,它调用的时候不是star方法启动新线程,而是直接调用run方法。

    2. invokeAndWait将你写的getFileLock塞到EventQueue中。

    3. Swing 事件机制采用Product Consumer模式 EDT不断的取EventQueue中的事件执行(消费者)。其他线程可以将事件塞入EventQueue中,比如鼠标点击Button是,将注册在BUttion的事件塞入EventQueue中。

    所以我们将getFileLock作为事件插入进去后 EDT分发是调用Thread.sleep(Integer.MAX_VALUE)就睡觉了,无暇管塞入EventQueue的其他事件了,比如关闭窗体。

    所以绝对不能将持有锁的逻辑塞到EventQueue,而应该放到外边main线程或者其他线程里面。

    提到invokeAndWait,还必须说说invokelater 这两个区别在哪里呢?

    invokeAndWait与invokelater区别: 看JDK代码:

 public static void invokeLater(Runnable runnable) {
        Toolkit.getEventQueue().postEvent(
            
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
    }

 public static void invokeAndWait(Runnable runnable)
             
throws InterruptedException, InvocationTargetException {

        
if (EventQueue.isDispatchThread()) {
            
throw new Error("Cannot call invokeAndWait from the event dispatcher thread");
        }

    
class AWTInvocationLock {}
        Object lock 
= new AWTInvocationLock();

        InvocationEvent event 
= 
            
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock,
                
true);

        
synchronized (lock) {
            Toolkit.getEventQueue().postEvent(event);
            lock.wait();
        }

        Throwable eventThrowable 
= event.getThrowable();
        
if (eventThrowable != null) {
            
throw new InvocationTargetException(eventThrowable);
        }
    }
invokelater:当在main方法中调用SwingUtils.invokelater,后,把事件塞入EventQueue就返回了,main线程不会阻塞。
invokeAndWait: 当在Main方法中调用SwingUtils.invokeAndWait 后,看代码片段:
        synchronized (lock) {
            Toolkit.getEventQueue().postEvent(event);
            lock.wait();
        }

main线程获得lock 后就wait()了,直到事件分发线程调用lock对象的notify唤醒main线程,否则main 就干等着吧。

这下明白了吧!
总之,对于我们问题最简单的方法就是是main线程里,或者在其他线程里处理。
posted @ 2009-10-26 11:48  kamome_s  阅读(663)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3