//: Counter3.java // Using the Runnable interface to turn the // main class into a thread. import java.awt.*; import java.awt.event.*; import java.applet.*;
public class Counter3 extends Applet implements Runnable { PRivate int count = 0; private boolean runFlag = true; private Thread selfThread = null; private Button onOff = new Button("Toggle"), start = new Button("Start"); private TextField t = new TextField(10); public void init() { add(t); start.addActionListener(new StartL()); add(start); onOff.addActionListener(new OnOffL()); add(onOff); } public void run() { while (true) { try { selfThread.sleep(100); } catch (InterruptedException e){} if(runFlag) t.setText(Integer.toString(count++)); } } class StartL implements ActionListener { public void actionPerformed(ActionEvent e) { if(selfThread == null) { selfThread = new Thread(Counter3.this); selfThread.start(); } } } class OnOffL implements ActionListener { public void actionPerformed(ActionEvent e) { runFlag = !runFlag; } } public static void main(String[] args) { Counter3 applet = new Counter3(); Frame aFrame = new Frame("Counter3"); 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); } } ///:~
現在run()位于類內,但它在init()結束以后仍處在“睡眠”狀態。若按下啟動按鈕,線程便會用多少有些曖昧的表達方式創建(若線程尚不存在): new Thread(Counter3.this); 若某樣東西有一個Runnable接口,實際只是意味著它有一個run()方法,但不存在與之相關的任何非凡東西——它不具有任何天生的線程處理能力,這與那些從Thread繼續的類是不同的。所以為了從一個Runnable對象產生線程,必須單獨創建一個線程,并為其傳遞Runnable對象;可為其使用一個非凡的構建器,并令其采用一個Runnable作為自己的參數使用。隨后便可為那個線程調用start(),如下所示: selfThread.start(); 它的作用是執行常規初始化操作,然后調用run()。 Runnable接口最大的一個優點是所有東西都從屬于相同的類。若需訪問什么東西,只需簡單地訪問它即可,不需要涉及一個獨立的對象。但為這種便利也是要付出代價的——只可為那個特定的對象運行單獨一個線程(盡管可創建那種類型的多個對象,或者在不同的類里創建其他對象)。 注重Runnable接口本身并不是造成這一限制的罪魁禍首。它是由于Runnable與我們的主類合并造成的,因為每個應用只能主類的一個對象。