<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 14.4 優先級 線程的優先級(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,此時應觀察到它的計數頻率顯著放慢。現在試著再次提高優先級,可以升高回線程組的優先級,但不能再高了。現在將線程組的優先級降低兩次。線程的優先級不會改變,但假若試圖提高或者降低它,就會發現這個優先級自動變成線程組的優先級。此外,新線程仍然具有一個默認優先級,即使它比組的優先級還要高(換句話說,不要指望利用組優先級來防止新線程擁有比現有的更高的優先級)。 最后,試著提高組的最大優先級。可以發現,這樣做是沒有效果的。我們只能減少線程組的最大優先級,而不能增大它。 ## 14.4.1 線程組 所有線程都隸屬于一個線程組。那可以是一個默認線程組,亦可是一個創建線程時明確指定的組。在創建之初,線程被限制到一個組里,而且不能改變到一個不同的組。每個應用都至少有一個線程從屬于系統線程組。若創建多個線程而不指定一個組,它們就會自動歸屬于系統線程組。 線程組也必須從屬于其他線程組。必須在構造器里指定新線程組從屬于哪個線程組。若在創建一個線程組的時候沒有指定它的歸屬,則同樣會自動成為系統線程組的一名屬下。因此,一個應用程序中的所有線程組最終都會將系統線程組作為自己的“父”。 之所以要提出“線程組”的概念,很難從字面上找到原因。這多少為我們討論的主題帶來了一些混亂。一般地說,我們認為是由于“安全”或者“保密”方面的理由才使用線程組的。根據Arnold和Gosling的說法:“線程組中的線程可以修改組內的其他線程,包括那些位于分層結構最深處的。一個線程不能修改位于自己所在組或者下屬組之外的任何線程”(注釋①)。然而,我們很難判斷“修改”在這兒的具體含義是什么。下面這個例子展示了位于一個“葉子組”內的線程能修改它所在線程組樹的所有線程的優先級,同時還能為這個“樹”內的所有線程都調用一個方法。 ``` ①:《The Java Programming Language》第179頁。該書由Arnold和Jams Gosling編著,Addison-Wesley于1996年出版 //: TestAccess.java // How threads can access other threads // in a parent thread group public class TestAccess { public static void main(String[] args) { ThreadGroup x = new ThreadGroup("x"), y = new ThreadGroup(x, "y"), z = new ThreadGroup(y, "z"); Thread one = new TestThread1(x, "one"), two = new TestThread2(z, "two"); } } class TestThread1 extends Thread { private int i; TestThread1(ThreadGroup g, String name) { super(g, name); } void f() { i++; // modify this thread System.out.println(getName() + " f()"); } } class TestThread2 extends TestThread1 { TestThread2(ThreadGroup g, String name) { super(g, name); start(); } public void run() { ThreadGroup g = getThreadGroup().getParent().getParent(); g.list(); Thread[] gAll = new Thread[g.activeCount()]; g.enumerate(gAll); for(int i = 0; i < gAll.length; i++) { gAll[i].setPriority(Thread.MIN_PRIORITY); ((TestThread1)gAll[i]).f(); } g.list(); } } ///:~ ``` 在`main()`中,我們創建了幾個`ThreadGroup`(線程組),每個都位于不同的“葉”上:`x`沒有參數,只有它的名字(一個`String`),所以會自動進入`system`(系統)線程組;`y`位于`x`下方,而`z`位于`y`下方。注意初始化是按照文字順序進行的,所以代碼合法。 有兩個線程創建之后進入了不同的線程組。其中,`TestThread1`沒有一個`run()`方法,但有一個`f()`,用于通知線程以及打印出一些東西,以便我們知道它已被調用。而`TestThread2`屬于`TestThread1`的一個子類,它的`run()`非常詳盡,要做許多事情。首先,它獲得當前線程所在的線程組,然后利用`getParent()`在繼承樹中向上移動兩級(這樣做是有道理的,因為我想把`TestThread2`在分級結構中向下移動兩級)。隨后,我們調用方法`activeCount()`,查詢這個線程組以及所有子線程組內有多少個線程,從而創建由指向`Thread`的引用構成的一個數組。`enumerate()`方法將指向所有這些線程的引用置入數組`gAll`里。然后在整個數組里遍歷,為每個線程都調用`f()`方法,同時修改優先級。這樣一來,位于一個“葉子”線程組里的線程就修改了位于父線程組的線程。 調試方法`list()`打印出與一個線程組有關的所有信息,把它們作為標準輸出。在我們對線程組的行為進行調查的時候,這樣做是相當有好處的。下面是程序的輸出: ``` java.lang.ThreadGroup[name=x,maxpri=10] Thread[one,5,x] java.lang.ThreadGroup[name=y,maxpri=10] java.lang.ThreadGroup[name=z,maxpri=10] Thread[two,5,z] one f() two f() java.lang.ThreadGroup[name=x,maxpri=10] Thread[one,1,x] java.lang.ThreadGroup[name=y,maxpri=10] java.lang.ThreadGroup[name=z,maxpri=10] Thread[two,1,z] ``` `list()`不僅打印出`ThreadGroup`或者`Thread`的類名,也打印出了線程組的名字以及它的最高優先級。對于線程,則打印出它們的名字,并接上線程優先級以及所屬的線程組。注意`list()`會對線程和線程組進行縮排處理,指出它們是未縮排的線程組的“子”。 大家可看到`f()`是由`TestThread2`的`run()`方法調用的,所以很明顯,組內的所有線程都是相當脆弱的。然而,我們只能訪問那些從自己的`system`線程組樹分支出來的線程,而且或許這就是所謂“安全”的意思。我們不能訪問其他任何人的系統線程樹。 (1) 線程組的控制 拋開安全問題不談,線程組最有用的一個地方就是控制:只需用單個命令即可完成對整個線程組的操作。下面這個例子演示了這一點,并對線程組內優先級的限制進行了說明。括號內的注釋數字便于大家比較輸出結果: ``` //: ThreadGroup1.java // How thread groups control priorities // of the threads inside them. public class ThreadGroup1 { public static void main(String[] args) { // Get the system thread & print its Info: ThreadGroup sys = Thread.currentThread().getThreadGroup(); sys.list(); // (1) // Reduce the system thread group priority: sys.setMaxPriority(Thread.MAX_PRIORITY - 1); // Increase the main thread priority: Thread curr = Thread.currentThread(); curr.setPriority(curr.getPriority() + 1); sys.list(); // (2) // Attempt to set a new group to the max: ThreadGroup g1 = new ThreadGroup("g1"); g1.setMaxPriority(Thread.MAX_PRIORITY); // Attempt to set a new thread to the max: Thread t = new Thread(g1, "A"); t.setPriority(Thread.MAX_PRIORITY); g1.list(); // (3) // Reduce g1's max priority, then attempt // to increase it: g1.setMaxPriority(Thread.MAX_PRIORITY - 2); g1.setMaxPriority(Thread.MAX_PRIORITY); g1.list(); // (4) // Attempt to set a new thread to the max: t = new Thread(g1, "B"); t.setPriority(Thread.MAX_PRIORITY); g1.list(); // (5) // Lower the max priority below the default // thread priority: g1.setMaxPriority(Thread.MIN_PRIORITY + 2); // Look at a new thread's priority before // and after changing it: t = new Thread(g1, "C"); g1.list(); // (6) t.setPriority(t.getPriority() -1); g1.list(); // (7) // Make g2 a child Threadgroup of g1 and // try to increase its priority: ThreadGroup g2 = new ThreadGroup(g1, "g2"); g2.list(); // (8) g2.setMaxPriority(Thread.MAX_PRIORITY); g2.list(); // (9) // Add a bunch of new threads to g2: for (int i = 0; i < 5; i++) new Thread(g2, Integer.toString(i)); // Show information about all threadgroups // and threads: sys.list(); // (10) System.out.println("Starting all threads:"); Thread[] all = new Thread[sys.activeCount()]; sys.enumerate(all); for(int i = 0; i < all.length; i++) if(!all[i].isAlive()) all[i].start(); // Suspends & Stops all threads in // this group and its subgroups: System.out.println("All threads started"); sys.suspend(); // Deprecated in Java 1.2 // Never gets here... System.out.println("All threads suspended"); sys.stop(); // Deprecated in Java 1.2 System.out.println("All threads stopped"); } } ///:~ ``` 下面的輸出結果已進行了適當的編輯,以便用一頁能夠裝下(`java.lang.`已被刪去),而且添加了適當的數字,與前面程序列表中括號里的數字對應: ``` (1) ThreadGroup[name=system,maxpri=10] Thread[main,5,system] (2) ThreadGroup[name=system,maxpri=9] Thread[main,6,system] (3) ThreadGroup[name=g1,maxpri=9] Thread[A,9,g1] (4) ThreadGroup[name=g1,maxpri=8] Thread[A,9,g1] (5) ThreadGroup[name=g1,maxpri=8] Thread[A,9,g1] Thread[B,8,g1] (6) ThreadGroup[name=g1,maxpri=3] Thread[A,9,g1] Thread[B,8,g1] Thread[C,6,g1] (7) ThreadGroup[name=g1,maxpri=3] Thread[A,9,g1] Thread[B,8,g1] Thread[C,3,g1] (8) ThreadGroup[name=g2,maxpri=3] (9) ThreadGroup[name=g2,maxpri=3] (10)ThreadGroup[name=system,maxpri=9] Thread[main,6,system] ThreadGroup[name=g1,maxpri=3] Thread[A,9,g1] Thread[B,8,g1] Thread[C,3,g1] ThreadGroup[name=g2,maxpri=3] Thread[0,6,g2] Thread[1,6,g2] Thread[2,6,g2] Thread[3,6,g2] Thread[4,6,g2] Starting all threads: All threads started ``` 所有程序都至少有一個線程在運行,而且`main()`采取的第一項行動便是調用`Thread`的一個`static`(靜態)方法,名為`currentThread()`。從這個線程開始,線程組將被創建,而且會為結果調用`list()`。輸出如下: ``` (1) ThreadGroup[name=system,maxpri=10] Thread[main,5,system] ``` 我們可以看到,主線程組的名字是`system`,而主線程的名字是`main`,而且它從屬于`system`線程組。 第二個練習顯示出`system`組的最高優先級可以減少,而且`main`線程可以增大自己的優先級: ``` (2) ThreadGroup[name=system,maxpri=9] Thread[main,6,system] ``` 第三個練習創建一個新的線程組,名為`g1`;它自動從屬于`system`線程組,因為并沒有明確指定它的歸屬關系。我們在`g1`內部放置了一個新線程,名為`A`。隨后,我們試著將這個組的最大優先級設到最高的級別,并將`A`的優先級也設到最高一級。結果如下: ``` (3) ThreadGroup[name=g1,maxpri=9] Thread[A,9,g1] ``` 可以看出,不可能將線程組的最大優先級設為高于它的父線程組。 第四個練習將`g1`的最大優先級降低兩級,然后試著把它升至`Thread.MAX_PRIORITY`。結果如下: ``` (4) ThreadGroup[name=g1,maxpri=8] Thread[A,9,g1] ``` 同樣可以看出,提高最大優先級的企圖是失敗的。我們只能降低一個線程組的最大優先級,而不能提高它。此外,注意線程A的優先級并未改變,而且它現在高于線程組的最大優先級。也就是說,線程組最大優先級的變化并不能對現有線程造成影響。 第五個練習試著將一個新線程設為最大優先級。如下所示: ``` (5) ThreadGroup[name=g1,maxpri=8] Thread[A,9,g1] Thread[B,8,g1] ``` 因此,新線程不能變到比最大線程組優先級還要高的一級。 這個程序的默認線程優先級是6;若新建一個線程,那就是它的默認優先級,而且不會發生變化,除非對優先級進行了特別的處理。練習六將把線程組的最大優先級降至默認線程優先級以下,看看在這種情況下新建一個線程會發生什么事情: ``` (6) ThreadGroup[name=g1,maxpri=3] Thread[A,9,g1] Thread[B,8,g1] Thread[C,6,g1] ``` 盡管線程組現在的最大優先級是3,但仍然用默認優先級6來創建新線程。所以,線程組的最大優先級不會影響默認優先級(事實上,似乎沒有辦法可以設置新線程的默認優先級)。 改變了優先級后,接下來試試將其降低一級,結果如下: ``` (7) ThreadGroup[name=g1,maxpri=3] Thread[A,9,g1] Thread[B,8,g1] Thread[C,3,g1] ``` 因此,只有在試圖改變優先級的時候,才會強迫遵守線程組最大優先級的限制。 我們在(8)和(9)中進行了類似的試驗。在這里,我們創建了一個新的線程組,名為`g2`,將其作為`g1`的一個子組,并改變了它的最大優先級。大家可以看到,`g2`的優先級無論如何都不可能高于`g1`: ``` (8) ThreadGroup[name=g2,maxpri=3] (9) ThreadGroup[name=g2,maxpri=3] ``` 也要注意在`g2`創建的時候,它會被自動設為`g1`的線程組最大優先級。 經過所有這些實驗以后,整個線程組和線程系統都會被打印出來,如下所示: ``` (10)ThreadGroup[name=system,maxpri=9] Thread[main,6,system] ThreadGroup[name=g1,maxpri=3] Thread[A,9,g1] Thread[B,8,g1] Thread[C,3,g1] ThreadGroup[name=g2,maxpri=3] Thread[0,6,g2] Thread[1,6,g2] Thread[2,6,g2] Thread[3,6,g2] Thread[4,6,g2] ``` 所以由線程組的規則所限,一個子組的最大優先級在任何時候都只能低于或等于它的父組的最大優先級。 本程序的最后一個部分演示了用于整組線程的方法。程序首先遍歷整個線程樹,并啟動每一個尚未啟動的線程。例如,`system`組隨后會被掛起(暫停),最后被中止(盡管用`suspend()`和`stop()`對整個線程組進行操作看起來似乎很有趣,但應注意這些方法在Java 1.2里都是被“反對”的)。但在掛起`system`組的同時,也掛起了`main`線程,而且整個程序都會關閉。所以永遠不會達到讓線程中止的那一步。實際上,假如真的中止了`main`線程,它會“拋”出一個`ThreadDeath`異常,所以我們通常不這樣做。由于`ThreadGroup`是從`Object`繼承的,其中包含了`wait()`方法,所以也能調用`wait(秒數×1000)`,令程序暫停運行任意秒數的時間。當然,事前必須在一個同步塊里取得對象鎖。 `ThreadGroup`類也提供了`suspend()`和`resume()`方法,所以能中止和啟動整個線程組和它的所有線程,也能中止和啟動它的子組,所有這些只需一個命令即可(再次提醒,`suspend()`和`resume()`都是Java 1.2所“反對”的)。 從表面看,線程組似乎有些讓人摸不著頭腦,但請注意我們很少需要直接使用它們。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看