• Java线程—如何解决Swing的单线程问题-----------Swing线程机制


    首先swing是单线程的,这个是这篇文章的前提,也是意义所在,当swing界面程序启动的时候,会启动3个进程,

    1、主线程

    2、系统工具包线程:负责捕获操作系统事件,然后将事件转换成swing的事件,然后发送到事件派发线程EDT

    3、事件派发线程(EDT):将事件派发到各个组件,并负责调用绘制方法更新界面


    所有的事件,例如键盘,鼠标事件,都会由工具包线程转换成swing事件,然后放到事件队列EventQueue中,而这个EventQueue的派发机制是由EDT来管理的。

    EDT管理队列

    所以任何修改组件状态的方法都应该在EDT中执行,包括构造方法。Swing这样的构造原理经常会造成的情况就是,在EDT中执行长时间的事件,使EDT不能及时响应更新界面的事件,就是所说的界面卡住,这种不光是新手就是比较熟练的程序员也会犯的一个错误。所以必须避免在EDT中执行长时间的操作,而避免的方法就是多线程,启动另外的线程来处理冗长的操作,比如操作数据库,读写文件等,在这过程中可能要更新界面来给用户以提示,比如显示一个进度条,过一段时间更新一下界面,但是在EDT以外的线程中更新界面都是无效的,这在前面已经说过,要更新界面就要将对界面的更新操作放到EDT中,但是事件又是在另外的线程中执行的,要解决这个问题就要使用SwingUtilities提供的两个静态方法了 invokeLater,invokeAndWait

    举例:

    invokeLater的使用

    class GetInfoThread extends Thread {
    
      Test applet;
      Runnable runx;
      int value;
    
      public GetInfoThread(final Test applet) {
       this.applet = applet;
       runx = new Runnable() {
        publicvoid run() {
         JProgressBar jpb = applet.getProgressBar();
         jpb.setValue(value);
        }
       };
      }
    
       publicvoid run() {
        while (true) {
         try {
          Thread.sleep(500);
          value = (int) (Math.random() * 100);
          System.out.println(value);
          SwingUtilities.invokeLater(runx);
         } catch (InterruptedException e) {
          e.printStackTrace();
         }
        }
       }
      }
     

    《》invokeAndWait和invokeLater的区别

    与invoikeLater一样,invokeAndWait也把可运行对象排入事件派发线程的队列中,invokeLater在把可运行的对象放入队列后就返回,而invokeAndWait一直等待直到提交的run方法执行完毕后才返回。如果操作2,必须得等到操作1完毕之后,才能够执行的话,则invokeAndWait方法是很有用的,那么我们就用invokeAndWait将操作1提交,之后再执行操作2就行了;

    invokeAndWait的使用

    class GetInfoThread extends Thread {
       
       Runnable getValue,setValue;
       int value,currentValue;
    
       public GetInfoThread(final Test applet){
    
       getValue=new Runnable(){
       publicvoid run(){
        JProgressBar pb=applet.getProgressBar();
        currentValue=pb.getValue();
        }
       };
    
       setValue=new Runnable(){
        publicvoid run(){
         JProgressBar pb=applet.getProgressBar();
         pb.setValue(value);
        }
       }
       }
    
       publicvoid 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){
          }
        }
       }
     

    注意:这两个方法的作用只是将一个更新界面的Runnable任务提交给EDT线程,EDT会在适当的时候进行调用以更新界面。

  • 相关阅读:
    [总结] XPO (eXpress Persistent Objects) 学习总结一
    [总结]工作中常用的正则表达式,有了它事半功倍!
    用JS实现页面滚动位置保持的方法
    [总结]TLF论坛全功略,下载指南!
    Javascript里使用Dom操作Xml
    。NET构架相关资源
    [收藏]关于用Asp.Net论坛发帖软件的实现
    匹配Unicode字符的正则表达式(中文)
    [转贴]如何实现TreeView的双击事件?
    [转贴]客户端不装adobe reader,打开pdf文件的插件
  • 原文地址:https://www.cnblogs.com/lxchma/p/6427506.html
Copyright © 2020-2023  润新知