深入浅出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线程里,或者在其他线程里处理。

转载于:https://www.cnblogs.com/kamome/archive/2009/10/26/1589842.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值