zoukankan      html  css  js  c++  java
  • java invokelater 以及invokeandwait

    SwingUtilities中invokeLater和invokeAndWait介绍
       在Java中Swing是线程不安全的,是单线程的设计,这样的造成结果就是:只能从事件派发线程访问将要在屏幕上绘制的Swing组件。事件派发线程是调用paint和update等回调方法的线程,它还是事件监听器接口中定义的事件处理方法,例如,ActionListener中的actionPerformed方法在事件派发线程中调用。
       Swing是事件驱动的,所以在回调函数中更新可见的GUI是很自然的事情,比如,有一个按钮被按下,项目列表需要更新时,则通常在与该按钮相关联的事件监听器的actionPerformed方法中来实现该列表的更新,从事件派发线程以外的线程中更新Swing组件是不正常的。
       有时需要从事件派发线程以外的线程中更新Swing组件,例如,在actionPerformed中有很费时的操作,需要很长时间才能返回,按钮激活后需要很长时间才能看到更新的列表,按钮会长时间保持按下的状态只到actionPerformed返回,一般说来耗时的操作不应该在事件处理方法中执行,因为事件处理返回之前,其他事件是不能触发的,界面类似于卡住的状况,所以在独立的线程上执行比较耗时的操作可能更好,这会立即更新用户界面和释放事件派发线程去派发其他的事件。
       SwingUtilities类提供了两个方法:invokeLate和invoteAndWait,它们都使事件派发线程上的可运行对象排队。当可运行对象排在事件派发队列的队首时,就调用其run方法。其效果是允许事件派发线程调用另一个线程中的任意一个代码块。
       只有从事件派发线程才能更新组件。
       程序示例:更新组件的错误方法
       startButton.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent e) {
        GetInfoThread t = new GetInfoThread(Test.this);
        t.start();
        startButton.setEnabled(false);
       }
      });
      
      class GetInfoThread extends Thread {
     Test applet;

     public GetInfoThread(Test applet) {
      this.applet = applet;
     }

      public void run() {
       while (true) {
        try {
         Thread.sleep(500);
         applet.getProgressBar().setValue(Math.random() * 100);
        } catch (InterruptedException e) {
         e.printStackTrace();
        }
       }
      }
     }
     错误分析:在actionPerformed中,监听器把按钮的允许状态设置为false,由于是在事件派发线程上调用actionPerformed,所以setEnabled是一个有效的操作,但是在GetInfoThread中设置进度条是一个危险的做法,因为事件派发线程以外的线程更新了进度条,所以运行是不正常的。

       1、invokeLater使用
        class GetInfoThread extends Thread {
      Test applet;
     
      Runnable runx;
     
      int value;

      public GetInfoThread(final Test applet) {
       this.applet = applet;
       runx = new Runnable() {
        public void run() {
         JProgressBar jpb = applet.getProgressBar();
         jpb.setValue(value);
        }
       };
      }

       public void run() {
        while (true) {
         try {
          Thread.sleep(500);
          value = (int) (Math.random() * 100);
          System.out.println(value);
          SwingUtilities.invokeLater(runx);
         } catch (InterruptedException e) {
          e.printStackTrace();
         }
        }
       }
      }
       
       2、invokeAndWait
       与invoikeLater一样,invokeAndWait也把可运行对象排入事件派发线程的队列中,invokeLater在把可运行的对象放入队列后就返回,而invokeAndWait一直等待知道已启动了可运行的run方法才返回。如果一个操作在另外一个操作执行之前必须从一个组件获得信息,则invokeAndWait方法是很有用的。
       class GetInfoThread extends Thread {
       Runnable getValue,setValue;
       int value,currentValue;
       public GetInfoThread(final Test applet){
       getValue=new Runnable(){
       public void run(){
        JProgressBar pb=applet.getProgressBar();
        currentValue=pb.getValue();
        }
       };
       setValue=new Runnable(){
        public void run(){
         JProgressBar pb=applet.getProgressBar();
         pb.setValue(value);
        }
       }
       }
       public void run(){
        while(true){
        try{
        Thread.currentThead().sleep(500);
        value=(int)(Math.random()*100);
        try{
        SwingUtilities.invokeAndWait(getValue);//直到getValue可运行的run方法返回后才返回
          }catch(Exception ex){
          }
          if(currentValue!=value){
          SwingUtilities.invokeLater(setValue);
          }
         }
         }catch(Exception ex){
          }
        }
       }
       invokeLater和invoikeAndWait的一个重要区别:可以从事件派发线程中调用invokeLater,却不能从事件派发线程中调用invokeAndWait,从事件派发线程调用invokeAndWait的问题是:invokeAndWait锁定调用它的线程,直到可运行对象从事件派发线程中派发出去并且该可运行的对象的run方法激活,如果从事件派发线程调用invoikeAndWait,则会发生死锁的状况,因为invokeAndWait正在等待事件派发,但是,由于是从事件派发线程中调用invokeAndWait,所以直到invokeAndWait返回后事件才能派发。
       ex)actionPerformed();返回的时候事件派发线程才能派发线程,而在actionPerformed中使用invokeAndWait则会导致actionPerformed不能返回。所以也就无法派发invokeAndWait中的线程。

    由于Swing是线程不安全的,所以,从事件派发线程之外的线程访问Swing组件是不安全的,SwingUtilities类提供这两种方法用于执行事件派发线程中的代码

  • 相关阅读:
    实例属性 类属性 实例域 类域
    研究数据集
    static 静态域 类域 静态方法 工厂方法 he use of the static keyword to create fields and methods that belong to the class, rather than to an instance of the class 非访问修饰符
    accessor mothod mutator mothod 更改器方法 访问器方法 类的方法可以访问类的任何一个对象的私有域!
    上钻 下钻 切片 转轴 降采样
    识别会话
    Performance Tuning Using Linux Process Management Commands
    Secure Hash Algorithm 3
    grouped differently across partitions
    spark 划分stage Wide vs Narrow Dependencies 窄依赖 宽依赖 解析 作业 job stage 阶段 RDD有向无环图拆分 任务 Task 网络传输和计算开销 任务集 taskset
  • 原文地址:https://www.cnblogs.com/prctice/p/4462254.html
Copyright © 2011-2022 走看看