本章早期建議:在將小程式或主 Frame 當作 Runnable 實作前,一定要好好思考。若採用該方式,**程式中只能使用一個該類型的執行緒**,限制靈活性,一旦需要多個同類型執行緒會遇到不必要麻煩。
當然,若必須從某類別繼承,且想使類別具備執行緒處理能力,Runnable 是正確方案。本章最後範例剖析此點,製作 RunnableCanvas 類別為自己繪製不同顏色。
//: ColorBoxes.java
import java.awt.*;
import java.awt.event.*;
class CBox extends Canvas implements Runnable {
private Thread t;
private int pause;
private static final Color[] colors = { /* 13 種顏色 */ };
private Color cColor = newColor();
private static final Color newColor() { return colors[(int)(Math.random() * colors.length)]; }
public void paint(Graphics g) {
g.setColor(cColor);
Dimension s = getSize();
g.fillRect(0, 0, s.width, s.height);
}
public CBox(int pause) {
this.pause = pause;
t = new Thread(this);
t.start();
}
public void run() {
while(true) {
cColor = newColor();
repaint();
try { t.sleep(pause); } catch(InterruptedException e) {}
}
}
}
public class ColorBoxes extends Frame {
public ColorBoxes(int pause, int grid) {
setTitle("ColorBoxes");
setLayout(new GridLayout(grid, grid));
for (int i = 0; i < grid * grid; i++) add(new CBox(pause));
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); }
});
}
public static void main(String[] args) {
int pause = 50; int grid = 8;
if(args.length > 0) pause = Integer.parseInt(args[0]);
if(args.length > 1) grid = Integer.parseInt(args[1]);
Frame f = new ColorBoxes(pause, grid);
f.setSize(500, 400);
f.setVisible(true);
}
} ///:~
Thread 物件傳入 Runnable,再呼叫 start()(在建構子完成)newColor() 產生隨機顏色repaint() → sleep()此設計極靈活,執行緒處理與每個 Canvas 元素緊密結合,理論上可產生任意多執行緒(實際受限於 JVM 能應付的執行緒數)。
此程式提供有趣基準,揭示不同 JVM 機制在速度上造成的戲劇性差異。