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() {
    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();
     }
    }
   }
  }

 

《》invokeAndWaitinvokeLater的區別

與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(){
   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){
      }
    }
   }

 

注意:這兩個方法的作用只是將一個更新界面的Runnable任務提交給EDT線程,EDT會在適當的時候進行調用以更新界面。

《》這就解決了Swing的線程不安全的問題

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM