程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 反應靈敏的用戶界面

反應靈敏的用戶界面

編輯:關於JAVA

作為我們的起點,請思考一個需要執行某些CPU密集型計算的程序。由於CPU“全心全意”為那些計算服務,所以對用戶的輸入十分遲鈍,幾乎沒有什麼反應。在這裡,我們用一個合成的applet/application(程序片/應用程序)來簡單顯示出一個計數器的結果:
 

//: Counter1.java
// A non-responsive user interface
package c14;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class Counter1 extends Applet {
  private int count = 0;
  private Button 
    onOff = new Button("Toggle"),
    start = new Button("Start");
  private TextField t = new TextField(10);
  private boolean runFlag = true;
  public void init() {
    add(t);
    start.addActionListener(new StartL());
    add(start);
    onOff.addActionListener(new OnOffL());
    add(onOff);
  }
  public void go() {
    while (true) {
      try {
        Thread.currentThread().sleep(100);
      } catch (InterruptedException e){}
      if(runFlag) 
        t.setText(Integer.toString(count++));
    }
  }
  class StartL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      go();
    }
  }
  class OnOffL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      runFlag = !runFlag;
    }
  }
  public static void main(String[] args) {
    Counter1 applet = new Counter1();
    Frame aFrame = new Frame("Counter1");
    aFrame.addWindowListener(
      new WindowAdapter() {
        public void windowClosing(WindowEvent e) {
          System.exit(0);
        }
      });
    aFrame.add(applet, BorderLayout.CENTER);
    aFrame.setSize(300,200);
    applet.init();
    applet.start();
    aFrame.setVisible(true);
  }
} ///:~

在這個程序中,AWT和程序片代碼都應是大家熟悉的,第13章對此已有很詳細的交待。go()方法正是程序全心全意服務的對待:將當前的count(計數)值置入TextField(文本字段)t,然後使count增值。
go()內的部分無限循環是調用sleep()。sleep()必須同一個Thread(線程)對象關聯到一起,而且似乎每個應用程序都有部分線程同它關聯(事實上,Java本身就是建立在線程基礎上的,肯定有一些線程會伴隨我們寫的應用一起運行)。所以無論我們是否明確使用了線程,都可利用Thread.currentThread()產生由程序使用的當前線程,然後為那個線程調用sleep()。注意,Thread.currentThread()是Thread類的一個靜態方法。
注意sleep()可能“擲”出一個InterruptException(中斷違例)——盡管產生這樣的違例被認為是中止線程的一種“惡意”手段,而且應該盡可能地杜絕這一做法。再次提醒大家,違例是為異常情況而產生的,而不是為了正常的控制流。在這裡包含了對一個“睡眠”線程的中斷,以支持未來的一種語言特性。
一旦按下start按鈕,就會調用go()。研究一下go(),你可能會很自然地(就象我一樣)認為它該支持多線程,因為它會進入“睡眠”狀態。也就是說,盡管方法本身“睡著”了,CPU仍然應該忙於監視其他按鈕“按下”事件。但有一個問題,那就是go()是永遠不會返回的,因為它被設計成一個無限循環。這意味著actionPerformed()根本不會返回。由於在第一個按鍵以後便陷入actionPerformed()中,所以程序不能再對其他任何事件進行控制(如果想出來,必須以某種方式“殺死”進程——最簡便的方式就是在控制台窗口按Ctrl+C鍵)。
這裡最基本的問題是go()需要繼續執行自己的操作,而與此同時,它也需要返回,以便actionPerformed()能夠完成,而且用戶界面也能繼續響應用戶的操作。但對象go()這樣的傳統方法來說,它卻不能在繼續的同時將控制權返回給程序的其他部分。這聽起來似乎是一件不可能做到的事情,就象CPU必須同時位於兩個地方一樣,但線程可以解決一切。“線程模型”(以及Java中的編程支持)是一種程序編寫規范,可在單獨一個程序裡實現幾個操作的同時進行。根據這一機制,CPU可為每個線程都分配自己的一部分時間。每個線程都“感覺”自己好象擁有整個CPU,但CPU的計算時間實際卻是在所有線程間分攤的。
線程機制多少降低了一些計算效率,但無論程序的設計,資源的均衡,還是用戶操作的方便性,都從中獲得了巨大的利益。綜合考慮,這一機制是非常有價值的。當然,如果本來就安裝了多塊CPU,那麼操作系統能夠自行決定為不同的CPU分配哪些線程,程序的總體運行速度也會變得更快(所有這些都要求操作系統以及應用程序的支持)。多線程和多任務是充分發揮多處理機系統能力的一種最有效的方式。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved