標籤:
“多線程最主要的一個用途是構建一個”反應靈敏“的介面”
--摘自《Java編程思想》
為了理解上面這句話,我們可以假設一種情景:假設有一個程式,該程式用來處理大量的數學運算,在多數情況下會佔用大量的cpu時間,
而在處理資料的過程中又嘗嘗需要與使用者進行互動,而如果進程中只有一個主線程的話,那麼程式每次都需要等到該主線程的任務完成後
才能對介面操作進行響應,這在通常的情況下是不可接受的。我們可以設想一個情景就是在程式運行時,如果突然有事需要離開(導師請你
出去吃飯,機會難得),這時你可能就需要點擊關閉按鈕,關閉程式,但是程式卻說我這還有200次迴圈要跑,沒空理你,等會我。如果遇到這種
情況,我們也有辦法,開啟工作管理員,結束進程,簡單有效但是卻很暴力。
接下來我們會舉兩個例子,一個是單線程對介面反應遲鈍的例子,一個是多線程(雙線程)對介面反應靈活的例子。
程式介面為,大致流程是當我們點擊start按鈕後,程式從0開始自增計數,並把結果顯示在輸入框中,而當我們點擊Toggle按鈕時,計數暫停,
再次點擊計數恢複。
為了體現單線程與多線程的差異,我們把這個計數的流程定義為一個死迴圈,即從0自增到無窮大,而Toggle按鈕則可以用來暫停這個迴圈。在例子一中
只有一個主線程,這就導致在計數迴圈時,程式不能夠對點擊按鈕的操作進行相應,我們也無法關閉該視窗。為瞭解決這個問題,在例子二中我們把這個計數
的過程放到一個單獨的線程中,而主線程則專門用來響應介面的操作,這時程式就可以正常運行。
(1)例子1
package hongqi.daiwei.lianyuan.java.multithread;import java.applet.Applet;import java.awt.BorderLayout;import java.awt.Button;import java.awt.Frame;import java.awt.TextField;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;public class Counter1 extends Applet { private int count = 0; private Button onOff = new Button("Toggle"); private Button 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); super.init(); } public void go(){ while(true){ try { Thread.currentThread(); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } 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(int argv, String argc[][]){ Counter1 applet = new Counter1(); Frame aFrame = new Frame("Counter1"); aFrame.add(applet, BorderLayout.CENTER); aFrame.setSize(300, 200); applet.init(); applet.start(); aFrame.setVisible(true); aFrame.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e) { System.exit(0); } }); }}View Code
(2)例子2
線程類:
package hongqi.daiwei.lianyuan.java.multithread;public class SeparateSubTask extends Thread { Counter2 c = null; private boolean flag = true; private int count = 0; public SeparateSubTask(Counter2 c){ this.c = c; this.start(); } public void invertFlag(){ flag = !flag; } public void run() { while(true){ try { sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if(flag){ c.t.setText(Integer.toString(count++)); } } } }View Code
主類:
package hongqi.daiwei.lianyuan.java.multithread;import java.applet.Applet;import java.awt.BorderLayout;import java.awt.Button;import java.awt.Frame;import java.awt.TextField;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;public class Counter1 extends Applet { private int count = 0; private Button onOff = new Button("Toggle"); private Button 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); super.init(); } public void go(){ while(true){ try { Thread.currentThread(); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } 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(int argv, String argc[][]){ Counter1 applet = new Counter1(); Frame aFrame = new Frame("Counter1"); aFrame.add(applet, BorderLayout.CENTER); aFrame.setSize(300, 200); applet.init(); applet.start(); aFrame.setVisible(true); aFrame.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e) { System.exit(0); } }); }}View Code
用多線程實現反應靈敏的介面(Java)