線程的優先級(Priority)告訴調試程序該線程的重要程度有多大。如果有大量線程都被堵塞,都在等候運行,調試程序會首先運行具有最高優先級的那個線程。然而,這並不表示優先級較低的線程不會運行(換言之,不會因為存在優先級而導致死鎖)。若線程的優先級較低,只不過表示它被准許運行的機會小一些而已。
可用getPriority()方法讀取一個線程的優先級,並用setPriority()改變它。在下面這個程序片中,大家會發現計數器的計數速度慢了下來,因為它們關聯的線程分配了較低的優先級:
//: Counter5.java // Adjusting the priorities of threads import java.awt.*; import java.awt.event.*; import java.applet.*; class Ticker2 extends Thread { private Button b = new Button("Toggle"), incPriority = new Button("up"), decPriority = new Button("down"); private TextField t = new TextField(10), pr = new TextField(3); // Display priority private int count = 0; private boolean runFlag = true; public Ticker2(Container c) { b.addActionListener(new ToggleL()); incPriority.addActionListener(new UpL()); decPriority.addActionListener(new DownL()); Panel p = new Panel(); p.add(t); p.add(pr); p.add(b); p.add(incPriority); p.add(decPriority); c.add(p); } class ToggleL implements ActionListener { public void actionPerformed(ActionEvent e) { runFlag = !runFlag; } } class UpL implements ActionListener { public void actionPerformed(ActionEvent e) { int newPriority = getPriority() + 1; if(newPriority > Thread.MAX_PRIORITY) newPriority = Thread.MAX_PRIORITY; setPriority(newPriority); } } class DownL implements ActionListener { public void actionPerformed(ActionEvent e) { int newPriority = getPriority() - 1; if(newPriority < Thread.MIN_PRIORITY) newPriority = Thread.MIN_PRIORITY; setPriority(newPriority); } } public void run() { while (true) { if(runFlag) { t.setText(Integer.toString(count++)); pr.setText( Integer.toString(getPriority())); } yield(); } } } public class Counter5 extends Applet { private Button start = new Button("Start"), upMax = new Button("Inc Max Priority"), downMax = new Button("Dec Max Priority"); private boolean started = false; private static final int SIZE = 10; private Ticker2[] s = new Ticker2[SIZE]; private TextField mp = new TextField(3); public void init() { for(int i = 0; i < s.length; i++) s[i] = new Ticker2(this); add(new Label("MAX_PRIORITY = " + Thread.MAX_PRIORITY)); add(new Label("MIN_PRIORITY = " + Thread.MIN_PRIORITY)); add(new Label("Group Max Priority = ")); add(mp); add(start); add(upMax); add(downMax); start.addActionListener(new StartL()); upMax.addActionListener(new UpMaxL()); downMax.addActionListener(new DownMaxL()); showMaxPriority(); // Recursively display parent thread groups: ThreadGroup parent = s[0].getThreadGroup().getParent(); while(parent != null) { add(new Label( "Parent threadgroup max priority = " + parent.getMaxPriority())); parent = parent.getParent(); } } public void showMaxPriority() { mp.setText(Integer.toString( s[0].getThreadGroup().getMaxPriority())); } class StartL implements ActionListener { public void actionPerformed(ActionEvent e) { if(!started) { started = true; for(int i = 0; i < s.length; i++) s[i].start(); } } } class UpMaxL implements ActionListener { public void actionPerformed(ActionEvent e) { int maxp = s[0].getThreadGroup().getMaxPriority(); if(++maxp > Thread.MAX_PRIORITY) maxp = Thread.MAX_PRIORITY; s[0].getThreadGroup().setMaxPriority(maxp); showMaxPriority(); } } class DownMaxL implements ActionListener { public void actionPerformed(ActionEvent e) { int maxp = s[0].getThreadGroup().getMaxPriority(); if(--maxp < Thread.MIN_PRIORITY) maxp = Thread.MIN_PRIORITY; s[0].getThreadGroup().setMaxPriority(maxp); showMaxPriority(); } } public static void main(String[] args) { Counter5 applet = new Counter5(); Frame aFrame = new Frame("Counter5"); aFrame.addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); aFrame.add(applet, BorderLayout.CENTER); aFrame.setSize(300, 600); applet.init(); applet.start(); aFrame.setVisible(true); } } ///:~
Ticker采用本章前面構造好的形式,但有一個額外的TextField(文本字段),用於顯示線程的優先級;以及兩個額外的按鈕,用於人為提高及降低優先級。
也要注意yield()的用法,它將控制權自動返回給調試程序(機制)。若不進行這樣的處理,多線程機制仍會工作,但我們會發現它的運行速度慢了下來(試試刪去對yield()的調用)。亦可調用sleep(),但假若那樣做,計數頻率就會改由sleep()的持續時間控制,而不是優先級。
Counter5中的init()創建了由10個Ticker2構成的一個數組;它們的按鈕以及輸入字段(文本字段)由Ticker2構建器置入窗體。Counter5增加了新的按鈕,用於啟動一切,以及用於提高和降低線程組的最大優先級。除此以外,還有一些標簽用於顯示一個線程可以采用的最大及最小優先級;以及一個特殊的文本字段,用於顯示線程組的最大優先級(在下一節裡,我們將全面討論線程組的問題)。最後,父線程組的優先級也作為標簽顯示出來。
按下“up”(上)或“down”(下)按鈕的時候,會先取得Ticker2當前的優先級,然後相應地提高或者降低。
運行該程序時,我們可注意到幾件事情。首先,線程組的默認優先級是5。即使在啟動線程之前(或者在創建線程之前,這要求對代碼進行適當的修改)將最大優先級降到5以下,每個線程都會有一個5的默認優先級。
最簡單的測試是獲取一個計數器,將它的優先級降低至1,此時應觀察到它的計數頻率顯著放慢。現在試著再次提高優先級,可以升高回線程組的優先級,但不能再高了。現在將線程組的優先級降低兩次。線程的優先級不會改變,但假若試圖提高或者降低它,就會發現這個優先級自動變成線程組的優先級。此外,新線程仍然具有一個默認優先級,即使它比組的優先級還要高(換句話說,不要指望利用組優先級來防止新線程擁有比現有的更高的優先級)。
最後,試著提高組的最大優先級。可以發現,這樣做是沒有效果的。我們只能減少線程組的最大優先級,而不能增大它。