麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

反應靈敏的用戶界面

2019-11-18 13:23:01
字體:
來源:轉載
供稿:網友

  反應靈敏的用戶界面
  作為我們的起點,請思考一個需要執行某些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 從線程繼續
  為創建一個線程,最簡單的方法就是從Thread類繼續。這個類包含了創建和運行線程所需的一切東西。Thread最重要的方法是run()。但為了使用run(),必須對其進行過載或者覆蓋,使其能充分按自己的吩咐行事。因此,run()屬于那些會與程序中的其他線程“并發”或“同時”執行的代碼。
  下面這個例子可創建任意數量的線程,并通過為每個線程分配一個獨一無二的編號(由一個靜態變量產生),從而對不同的線程進行跟蹤。Thread的run()方法在這里得到了覆蓋,每通過一次循環,計數就減1——計數為0時則完成循環(此時一旦返回run(),線程就中止運行)。
  //: 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()方法幾乎肯定含有某種形式的循環——它們會一直持續到線程不再需要為止。因此,我們必須規定特定的條件,以便中斷并退出這個循環(或者在上述的例子中,簡單地從run()返回即可)。run()通常采用一種無限循環的形式。也就是說,通過阻止外部發出對線程的stop()或者destroy()調用,它會永遠運行下去(直到程序完成)。
  在main()中,可看到創建并運行了大量線程。Thread包含了一個非凡的方法,叫作start(),它的作用是對線程進行非凡的初始化,然后調用run()。所以整個步驟包括:調用構建器來構建對象,然后用start()配置線程,再調用run()。假如不調用start()——假如適當的話,可在構建器那樣做——線程便永遠不會啟動。
  下面是該程序某一次運行的輸出(注重每次運行都會不同):
  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)
  可注重到這個例子中到處都調用了sleep(),然而輸出結果指出每個線程都獲得了屬于自己的那一部分CPU執行時間。從中可以看出,盡管sleep()依靠一個線程的存在來執行,但卻與答應或禁止線程無關。它只不過是另一個不同的方法而已。
  亦可看出線程并不是按它們創建時的順序運行的。事實上,CPU處理一個現有線程集的順序是不確定的——除非我們親自介入,并用Thread的setPriority()方法調整它們的優先級。
  main()創建Thread對象時,它并未捕捉任何一個對象的句柄。普通對象對于垃圾收集來說是一種“公平競賽”,但線程卻并非如此。每個線程都會“注冊”自己,所以某處實際存在著對它的一個引用。這樣一來,垃圾收集器便只好對它“瞠目以對”了。
  2 針對用戶界面的多線程
  現在,我們也許能用一個線程解決在Counter1.java中出現的問題。采用的一個技巧便是在一個線程的run()方法中放置“子任務”——亦即位于go()內的循環。一旦用戶按下Start按鈕,線程就會啟動,但馬上結束線程的創建。這樣一來,盡管線程仍在運行,但程序的主要工作卻能得以繼續(等候并響應用戶界面的事件)。下面是具體的代碼:
  //: Counter2.java
  // A responsive user interface with threads
  import java.awt.*;
  import java.awt.event.*;<

上一篇:共享有限的資源

下一篇:為何會堵塞

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 四季久久免费一区二区三区四区 | 免费毛片小视频 | 婷婷久久久久久 | 娇妻被各种姿势c到高潮小说 | 亚洲视频在线视频 | 轻点插视频 | 久久艹精品视频 | 国产一区毛片 | 国产一及毛片 | 色阁五月| 久久精品亚洲欧美日韩精品中文字幕 | 国产噜噜噜噜久久久久久久久 | 国产成人免费高清激情视频 | 国产一区在线免费 | 国产三级精品最新在线 | 九九热精品免费视频 | 一级毛片在线看 | 国产国语毛片 | 超碰97人人艹 | 在线成人影视 | 免费观看黄色片视频 | chinese xvideos gay | 福利在线影院 | 中文日韩欧美 | 久久精品国产精品亚洲 | 久草最新在线 | 欧美a级一区二区 | 久久久久久久久浪潮精品 | 午夜精品福利视频 | 一级黄色a视频 | 一级片九九 | 国产91九色视频 | 国产一级小视频 | 国产精品久久久久久久久久久久午夜 | 香蕉成人在线视频 | 久久综合九色综合久久久精品综合 | 成人免费在线观看视频 | 日韩视频在线观看免费 | 免费毛片小视频 | 日日操夜夜透 | 久久经典视频 |