熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

針對用戶界面的多線程

2022-06-13   來源: Java高級技術 

  現在我們也許能用一個線程解決在Counterjava中出現的問題采用的一個技巧便是在一個線程的run()方法中放置子任務——亦即位於go()內的循環一旦用戶按下Start按鈕線程就會啟動但馬上結束線程的創建這樣一來盡管線程仍在運行但程序的主要工作卻能得以繼續(等候並響應用戶界面的事件)下面是具體的代碼
  //: Counterjava
  // A responsive user interface with threads
  import javaawt*;
  import javaawtevent*;
  import javaapplet*;
  class SeparateSubTask extends Thread {
   private int count = ;
   private Counter c;
   private boolean runFlag = true;
   public SeparateSubTask(Counter c) {
   thisc = c;
   start();
   }
   public void invertFlag() { runFlag = !runFlag;}
   public void run() {
   while (true) {
   try {
   sleep();
   } catch (InterruptedException e){}
   if(runFlag)
   ctsetText(IntegertoString(count++));
   }
   }
  }
  public class Counter extends Applet {
   TextField t = new TextField();
   private SeparateSubTask sp = null;
   private Button
   onOff = new Button(Toggle)
   start = new Button(Start);
   public void init() {
   add(t);
   startaddActionListener(new StartL());
   add(start);
   onOffaddActionListener(new OnOffL());
   add(onOff);
   }
   class StartL implements ActionListener {
   public void actionPerformed(ActionEvent e) {
   if(sp == null)
   sp = new SeparateSubTask(Counterthis);
   }
   }
   class OnOffL implements ActionListener {
   public void actionPerformed(ActionEvent e) {
   if(sp != null)
   spinvertFlag();
   }
   }
   public static void main(String[] args) {
   Counter applet = new Counter();
   Frame aFrame = new Frame(Counter);
   aFrameaddWindowListener(
   new WindowAdapter() {
   public void windowClosing(WindowEvent e) {
   Systemexit();
   }
   });
   aFrameadd(applet BorderLayoutCENTER);
   aFramesetSize();
   appletinit();
   appletstart();
   aFramesetVisible(true);
   }
  }
  現在Counter變成了一個相當直接的程序它的唯一任務就是設置並管理用戶界面但假若用戶現在按下Start按鈕卻不會真正調用一個方法此時不是創建類的一個線程而是創建SeparateSubTask然後繼續Counter事件循環注意此時會保存SeparateSubTask的句柄以便我們按下onOff按鈕的時候能正常地切換位於SeparateSubTask內部的runFlag(運行標志)隨後那個線程便可啟動(當它看到標志的時候)然後將自己中止(亦可將SeparateSubTask設為一個內部類來達到這一目的)
  SeparateSubTask類是對Thread的一個簡單擴展它帶有一個構建器(其中保存了Counter句柄然後通過調用start()來運行線程)以及一個run()——本質上包含了Counterjava的go()內的代碼由於SeparateSubTask知道自己容納了指向一個Counter的句柄所以能夠在需要的時候介入並訪問Counter的TestField(文本字段)
  按下onOff按鈕幾乎立即能得到正確的響應當然這個響應其實並不是立即發生的它畢竟和那種由中斷驅動的系統不同只有線程擁有CPU的執行時間並注意到標記已發生改變計數器才會停止
  用內部類改善代碼
  下面說說題外話請大家注意一下SeparateSubTask和Counter類之間發生的結合行為SeparateSubTask同Counter親密地結合到了一起——它必須持有指向自己Counter對象的一個句柄以便自己能回調和操縱它但兩個類並不是真的合並為單獨一個類(盡管在下一節中我們會講到Java確實提供了合並它們的方法)因為它們各自做的是不同的事情而且是在不同的時間創建的但不管怎樣它們依然緊密地結合到一起(更准確地說應該叫聯合所以使程序代碼多少顯得有些笨拙在這種情況下一個內部類可以顯著改善代碼的可讀性和執行效率
  //: Counterijava
  // Counter using an inner class for the thread
  import javaawt*;
  import javaawtevent*;
  import javaapplet*;
  public class Counteri extends Applet {
   private class SeparateSubTask extends Thread {
   int count = ;
   boolean runFlag = true;
   SeparateSubTask() { start(); }
   public void run() {
   while (true) {
   try {
   sleep();
   } catch (InterruptedException e){}
   if(runFlag)
   tsetText(IntegertoString(count++));
   }
   }
   }
   private SeparateSubTask sp = null;
   private TextField t = new TextField();
   private Button
   onOff = new Button(Toggle)
   start = new Button(Start);
   public void init() {
   add(t);
   startaddActionListener(new StartL());
   add(start);
   onOffaddActionListener(new OnOffL());
   add(onOff);
   }
   class StartL implements ActionListener {
   public void actionPerformed(ActionEvent e) {
   if(sp == null)
   sp = new SeparateSubTask();
   }
   }
   class OnOffL implements ActionListener {
   public void actionPerformed(ActionEvent e) {
   if(sp != null)
   sprunFlag = !sprunFlag; // invertFlag();
   }
   }
   public static void main(String[] args) {
   Counteri applet = new Counteri();
   Frame aFrame = new Frame(Counteri);
   aFrameaddWindowListener(
   new WindowAdapter() {
   public void windowClosing(WindowEvent e) {
   Systemexit();
   }
   });
   aFrameadd(applet BorderLayoutCENTER);
   aFramesetSize();
   appletinit();
   appletstart();
   aFramesetVisible(true);
   }
  }
  這個SeparateSubTask名字不會與前例中的SeparateSubTask沖突——即使它們都在相同的目錄裡——因為它已作為一個內部類隱藏起來大家亦可看到內部類被設為private(私有)屬性這意味著它的字段和方法都可獲得默認的訪問權限(run()除外它必須設為public因為它在基礎類中是公開的)除Counteri之外其他任何方面都不可訪問private內部類而且由於兩個類緊密結合在一起所以很容易放寬它們之間的訪問限制在SeparateSubTask中我們可看到invertFlag()方法已被刪去因為Counteri現在可以直接訪問runFlag
  此外注意SeparateSubTask的構建器已得到了簡化——它現在唯一的用外就是啟動線程Counteri對象的句柄仍象以前那樣得以捕獲但不再是通過人工傳遞和引用外部對象來達到這一目的此時的內部類機制可以自動照料它在run()中可看到對t的訪問是直接進行的似乎它是SeparateSubTask的一個字段父類中的t字段現在可以變成private因為SeparateSubTask能在未獲任何特殊許可的前提下自由地訪問它——而且無論如何都該盡可能地把字段變成私有屬性以防來自類外的某種力量不慎地改變它們
  無論在什麼時候只要注意到類相互之間結合得比較緊密就可考慮利用內部類來改善代碼的編寫與維護
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27450.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.