zoukankan      html  css  js  c++  java
  • wingUtilities中invokeLater和invokeAndWait的介绍[转]

    在Java中Swing是线程不安全的,是单线程的设计,这样的造成结果就是:只能从事件派发线程访问将要在屏幕上绘制的Swing组件。事件派发线程是调用paint和update等回调方法的线程,它还是事件监听器接口中定义的事件处理方法,例如,ActionListener中的actionPerformed方法在事件派发线程中调用。

      Swing是事件驱动的,所以在回调函数中更新可见的GUI是很自然的事情,比如,有一个按钮被按下,项目列表需要更新时,则通常在与该按钮相关联的事件监听器的actionPerformed方法中来实现该列表的更新,从事件派发线程以外的线程中更新Swing组件是不正常的。

      有时需要从事件派发线程以外的线程中更新Swing组件,例如,在actionPerformed中有很费时的操作,需要很长时间才能返回,按钮激活后需要很长时间才能看到更新的列表,按钮会长时间保持按下的状态只到actionPerformed返回,一般说来耗时的操作不应该在事件处理方法中执行,因为事件处理返回之前,其他事件是不能触发的,界面类似于卡住的状况,所以在独立的线程上执行比较耗时的操作可能更好,这会立即更新用户界面和释放事件派发线程去派发其他的事件。

      SwingUtilities类提供了两个方法:invokeLate和invoteAndWait,它们都使事件派发线程上的可运行对象排队。当可运行对象排在事件派发队列的队首时,就调用其run方法。其效果是允许事件派发线程调用另一个线程中的任意一个代码块。

      只有从事件派发线程才能更新组件。

      程序示例:更新组件的错误方法

    双击代码全选
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     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使用

    双击代码全选
    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
    26
     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方法是很有用的。

    双击代码全选
    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    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类提供这两种方法用于执行事件派发线程中的代码

  • 相关阅读:
    HOJ 2139 Spiderman's workout(动态规划)
    FZU 2107 Hua Rong Dao(dfs)
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 无向连通图最少包含多少条边
    Java 第十一届 蓝桥杯 省模拟赛 无向连通图最少包含多少条边
  • 原文地址:https://www.cnblogs.com/buxianghe/p/2714919.html
Copyright © 2011-2022 走看看