国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

反應(yīng)靈敏的用戶界面

2019-11-18 13:23:01
字體:
供稿:網(wǎng)友

  反應(yīng)靈敏的用戶界面
  作為我們的起點(diǎn),請(qǐng)思考一個(gè)需要執(zhí)行某些CPU密集型計(jì)算的程序。由于CPU“全心全意”為那些計(jì)算服務(wù),所以對(duì)用戶的輸入十分遲鈍,幾乎沒有什么反應(yīng)。在這里,我們用一個(gè)合成的applet/application(程序片/應(yīng)用程序)來簡(jiǎn)單顯示出一個(gè)計(jì)數(shù)器的結(jié)果:
  //: 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);
   }
  } //
  在這個(gè)程序中,AWT和程序片代碼都應(yīng)是大家熟悉的,第13章對(duì)此已有很具體的交待。go()方法正是程序全心全意服務(wù)的對(duì)待:將當(dāng)前的count(計(jì)數(shù))值置入TextField(文本字段)t,然后使count增值。
  go()內(nèi)的部分無限循環(huán)是調(diào)用sleep()。sleep()必須同一個(gè)Thread(線程)對(duì)象關(guān)聯(lián)到一起,而且似乎每個(gè)應(yīng)用程序都有部分線程同它關(guān)聯(lián)(事實(shí)上,Java本身就是建立在線程基礎(chǔ)上的,肯定有一些線程會(huì)伴隨我們寫的應(yīng)用一起運(yùn)行)。所以無論我們是否明確使用了線程,都可利用Thread.currentThread()產(chǎn)生由程序使用的當(dāng)前線程,然后為那個(gè)線程調(diào)用sleep()。注重,Thread.currentThread()是Thread類的一個(gè)靜態(tài)方法。
  注重sleep()可能“擲”出一個(gè)InterruptException(中斷違例)——盡管產(chǎn)生這樣的違例被認(rèn)為是中止線程的一種“惡意”手段,而且應(yīng)該盡可能地杜絕這一做法。再次提醒大家,違例是為異常情況而產(chǎn)生的,而不是為了正常的控制流。在這里包含了對(duì)一個(gè)“睡眠”線程的中斷,以支持未來的一種語言特性。
  一旦按下start按鈕,就會(huì)調(diào)用go()。研究一下go(),你可能會(huì)很自然地(就象我一樣)認(rèn)為它該支持多線程,因?yàn)樗鼤?huì)進(jìn)入“睡眠”狀態(tài)。也就是說,盡管方法本身“睡著”了,CPU仍然應(yīng)該忙于監(jiān)視其他按鈕“按下”事件。但有一個(gè)問題,那就是go()是永遠(yuǎn)不會(huì)返回的,因?yàn)樗辉O(shè)計(jì)成一個(gè)無限循環(huán)。這意味著actionPerformed()根本不會(huì)返回。由于在第一個(gè)按鍵以后便陷入actionPerformed()中,所以程序不能再對(duì)其他任何事件進(jìn)行控制(假如想出來,必須以某種方式“殺死”進(jìn)程——最簡(jiǎn)便的方式就是在控制臺(tái)窗口按Ctrl+C鍵)。
  這里最基本的問題是go()需要繼續(xù)執(zhí)行自己的操作,而與此同時(shí),它也需要返回,以便actionPerformed()能夠完成,而且用戶界面也能繼續(xù)響應(yīng)用戶的操作。但對(duì)象go()這樣的傳統(tǒng)方法來說,它卻不能在繼續(xù)的同時(shí)將控制權(quán)返回給程序的其他部分。這聽起來似乎是一件不可能做到的事情,就象CPU必須同時(shí)位于兩個(gè)地方一樣,但線程可以解決一切。“線程模型”(以及Java中的編程支持)是一種程序編寫規(guī)范,可在單獨(dú)一個(gè)程序里實(shí)現(xiàn)幾個(gè)操作的同時(shí)進(jìn)行。根據(jù)這一機(jī)制,CPU可為每個(gè)線程都分配自己的一部分時(shí)間。每個(gè)線程都“感覺”自己好象擁有整個(gè)CPU,但CPU的計(jì)算時(shí)間實(shí)際卻是在所有線程間分?jǐn)偟摹?br />  線程機(jī)制多少降低了一些計(jì)算效率,但無論程序的設(shè)計(jì),資源的均衡,還是用戶操作的方便性,都從中獲得了巨大的利益。綜合考慮,這一機(jī)制是非常有價(jià)值的。當(dāng)然,假如本來就安裝了多塊CPU,那么操作系統(tǒng)能夠自行決定為不同的CPU分配哪些線程,程序的總體運(yùn)行速度也會(huì)變得更快(所有這些都要求操作系統(tǒng)以及應(yīng)用程序的支持)。多線程和多任務(wù)是充分發(fā)揮多處理機(jī)系統(tǒng)能力的一種最有效的方式。
  1 從線程繼續(xù)
  為創(chuàng)建一個(gè)線程,最簡(jiǎn)單的方法就是從Thread類繼續(xù)。這個(gè)類包含了創(chuàng)建和運(yùn)行線程所需的一切東西。Thread最重要的方法是run()。但為了使用run(),必須對(duì)其進(jìn)行過載或者覆蓋,使其能充分按自己的吩咐行事。因此,run()屬于那些會(huì)與程序中的其他線程“并發(fā)”或“同時(shí)”執(zhí)行的代碼。
  下面這個(gè)例子可創(chuàng)建任意數(shù)量的線程,并通過為每個(gè)線程分配一個(gè)獨(dú)一無二的編號(hào)(由一個(gè)靜態(tài)變量產(chǎn)生),從而對(duì)不同的線程進(jìn)行跟蹤。Thread的run()方法在這里得到了覆蓋,每通過一次循環(huán),計(jì)數(shù)就減1——計(jì)數(shù)為0時(shí)則完成循環(huán)(此時(shí)一旦返回run(),線程就中止運(yùn)行)。
  //: SimpleThread.java
  // Very simple Threading example
  public class SimpleThread extends Thread {
   private int countDown = 5;
   private int threadNumber;
   private static int threadCount = 0;
   public SimpleThread() {
    threadNumber = ++threadCount;
    System.out.println("Making " + threadNumber);
   }
   public void run() {
    while(true) {
     System.out.println("Thread " +
      threadNumber + "(" + countDown + ")");
     if(--countDown == 0) return;
    }
   }
   public static void main(String[] args) {
    for(int i = 0; i < 5; i++)
     new SimpleThread().start();
    System.out.println("All Threads Started");
   }
  }
  run()方法幾乎肯定含有某種形式的循環(huán)——它們會(huì)一直持續(xù)到線程不再需要為止。因此,我們必須規(guī)定特定的條件,以便中斷并退出這個(gè)循環(huán)(或者在上述的例子中,簡(jiǎn)單地從run()返回即可)。run()通常采用一種無限循環(huán)的形式。也就是說,通過阻止外部發(fā)出對(duì)線程的stop()或者destroy()調(diào)用,它會(huì)永遠(yuǎn)運(yùn)行下去(直到程序完成)。
  在main()中,可看到創(chuàng)建并運(yùn)行了大量線程。Thread包含了一個(gè)非凡的方法,叫作start(),它的作用是對(duì)線程進(jìn)行非凡的初始化,然后調(diào)用run()。所以整個(gè)步驟包括:調(diào)用構(gòu)建器來構(gòu)建對(duì)象,然后用start()配置線程,再調(diào)用run()。假如不調(diào)用start()——假如適當(dāng)?shù)脑挘稍跇?gòu)建器那樣做——線程便永遠(yuǎn)不會(huì)啟動(dòng)。
  下面是該程序某一次運(yùn)行的輸出(注重每次運(yùn)行都會(huì)不同):
  Making 1
  Making 2
  Making 3
  Making 4
  Making 5
  Thread 1(5)
  Thread 1(4)
  Thread 1(3)
  Thread 1(2)
  Thread 2(5)
  Thread 2(4)
  Thread 2(3)
  Thread 2(2)
  Thread 2(1)
  Thread 1(1)
  All Threads Started
  Thread 3(5)
  Thread 4(5)
  Thread 4(4)
  Thread 4(3)
  Thread 4(2)
  Thread 4(1)
  Thread 5(5)
  Thread 5(4)
  Thread 5(3)
  Thread 5(2)
  Thread 5(1)
  Thread 3(4)
  Thread 3(3)
  Thread 3(2)
  Thread 3(1)
  可注重到這個(gè)例子中到處都調(diào)用了sleep(),然而輸出結(jié)果指出每個(gè)線程都獲得了屬于自己的那一部分CPU執(zhí)行時(shí)間。從中可以看出,盡管sleep()依靠一個(gè)線程的存在來執(zhí)行,但卻與答應(yīng)或禁止線程無關(guān)。它只不過是另一個(gè)不同的方法而已。
  亦可看出線程并不是按它們創(chuàng)建時(shí)的順序運(yùn)行的。事實(shí)上,CPU處理一個(gè)現(xiàn)有線程集的順序是不確定的——除非我們親自介入,并用Thread的setPriority()方法調(diào)整它們的優(yōu)先級(jí)。
  main()創(chuàng)建Thread對(duì)象時(shí),它并未捕捉任何一個(gè)對(duì)象的句柄。普通對(duì)象對(duì)于垃圾收集來說是一種“公平競(jìng)賽”,但線程卻并非如此。每個(gè)線程都會(huì)“注冊(cè)”自己,所以某處實(shí)際存在著對(duì)它的一個(gè)引用。這樣一來,垃圾收集器便只好對(duì)它“瞠目以對(duì)”了。
  2 針對(duì)用戶界面的多線程
  現(xiàn)在,我們也許能用一個(gè)線程解決在Counter1.java中出現(xiàn)的問題。采用的一個(gè)技巧便是在一個(gè)線程的run()方法中放置“子任務(wù)”——亦即位于go()內(nèi)的循環(huán)。一旦用戶按下Start按鈕,線程就會(huì)啟動(dòng),但馬上結(jié)束線程的創(chuàng)建。這樣一來,盡管線程仍在運(yùn)行,但程序的主要工作卻能得以繼續(xù)(等候并響應(yīng)用戶界面的事件)。下面是具體的代碼:
  //: Counter2.java
  // A responsive user interface with threads
  import java.awt.*;
  import java.awt.event.*;<

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 元氏县| 福泉市| 通道| 文昌市| 吴川市| 建始县| 林芝县| 册亨县| 溧水县| 涪陵区| 永丰县| 文昌市| 焦作市| 金乡县| 武威市| 新安县| 多伦县| 西城区| 陇南市| 无为县| 松桃| 台东市| 关岭| 海兴县| 教育| 奉新县| 晋州市| 社旗县| 连南| 白玉县| 长武县| 丰宁| 芒康县| 石屏县| 沐川县| 招远市| 青河县| 房产| 崇明县| 铁岭县| 襄城县|