1. 程式人生 > >Java執行緒: 執行緒排程

Java執行緒: 執行緒排程

 執行緒排程是Java多執行緒的核心,只有好的排程,才能充分發揮系統的效能,提高程式的執行效率。

一、休眠

休眠的目的是使執行緒讓出CPU的最簡單做法,執行緒休眠的時候,會將CPU交給其他執行緒,以便輪換執行,休眠一定時間後,執行緒會甦醒,進入準備狀態等待執行。執行緒的休眠方法是Thread.sleep(long millis)和Thread.sleep(long millis,int nanos),均為靜態方法,呼叫sleep休眠的哪個執行緒呢?哪個執行緒呼叫sleep,哪個執行緒休眠。例子:

  執行緒1休眠後,讓出CPU,執行緒2執行,執行緒2執行完後,執行緒2休眠,讓出CPU供執行緒1執行,(此時執行緒1已經休眠結束,在等待狀態),如此迴圈執行,直到結束。

  SleepTest.java

 1 package Thread;
 2 
 3 public class SleepTest {
 4     public static void main(String[] args){
 5         Thread t1=new MyThread_1();
 6         Thread t2=new Thread(new MyRunnable1());
 7         t1.start();
 8         t2.start();
 9     }
10 }
11 class MyThread_1 extends Thread{
12 public void run(){ 13 for(int i=0;i<3;i++){ 14 System.out.println("執行緒1第"+i+"次執行!"); 15 try{ 16 Thread.sleep(500);//影響的是執行速度。 17 }catch(InterruptedException e){ 18 e.printStackTrace(); 19 } 20 } 21 }
22 } 23 class MyRunnable1 implements Runnable{ 24 public void run(){ 25 for(int i=0;i<3;i++){ 26 System.out.println("執行緒2第"+i+"次執行!"); 27 try{ 28 Thread.sleep(500); 29 }catch(InterruptedException e){ 30 e.printStackTrace(); 31 } 32 } 33 } 34 }
View Code

  結果為:

1 執行緒1第0次執行!
2 執行緒2第0次執行!
3 執行緒1第1次執行!
4 執行緒2第1次執行!
5 執行緒2第2次執行!
6 執行緒1第2次執行!

二、執行緒優先順序

  可以用setPriority方法提高或降低任何一個執行緒的優先順序,具體為1-10之間的數,預設優先順序為5。並非優先順序低的執行緒沒有機會執行,優先順序高低只是代表了執行機會的大小。每一個執行緒都有一個優先順序。一個執行緒繼承它父執行緒的優先順序,它們的優先順序相同。例子:

  PriorityTest.java

 1 package Thread;
 2 public class PriorityTest {
 3     public static void main(String[] args){
 4         Thread t1=new MyThread_2();
 5         Thread t2=new Thread(new MyRunnable2());
 6         t1.setPriority(10);
 7         t2.setPriority(1);
 8         t2.start();
 9         t1.start();
10         
11     }
12 }
13 class MyThread_2 extends Thread{
14     public void run(){
15         for(int i=0;i<10;i++){
16             System.out.println("執行緒1第"+i+"次執行!");
17             try{
18                 Thread.sleep(100);//影響的是執行速度。
19             }catch(InterruptedException e){
20                 e.printStackTrace();
21             }
22         }
23     }
24 }
25 class MyRunnable2 implements Runnable{
26     public void run(){
27         for(int i=0;i<10;i++){
28             System.out.println("執行緒2第"+i+"次執行!");
29             try{
30                 Thread.sleep(100);
31             }catch(InterruptedException e){
32                 e.printStackTrace();
33             }
34         }
35     }
36 }
View Code

  結果為:

 1 執行緒1第0次執行!
 2 執行緒2第0次執行!
 3 執行緒1第1次執行!
 4 執行緒2第1次執行!
 5 執行緒1第2次執行!
 6 執行緒2第2次執行!
 7 執行緒1第3次執行!
 8 執行緒2第3次執行!
 9 執行緒1第4次執行!
10 執行緒2第4次執行!
11 執行緒1第5次執行!
12 執行緒2第5次執行!
13 執行緒2第6次執行!
14 執行緒1第6次執行!
15 執行緒1第7次執行!
16 執行緒2第7次執行!
17 執行緒1第8次執行!
18 執行緒2第8次執行!
19 執行緒1第9次執行!
20 執行緒2第9次執行!
View Code

 三、守護執行緒

  呼叫t.setDaemon(true)將執行緒轉換成守護執行緒。守護執行緒的唯一用途是為其他執行緒提供服務。比如說,JVM的垃圾回收、記憶體管理等執行緒都是守護執行緒。計時執行緒就是一個例子,它定時的傳送“計時器滴答”訊號給其他執行緒或清空過時的快取記憶體項的執行緒,最後只剩下守護執行緒時,JVM就退出了。

  setDaemon方法的詳細說明:

 1 public final void setDaemon(boolean on)將該執行緒標記為守護執行緒或使用者執行緒。當正在執行的執行緒都是守護執行緒時,JVM退出。
 2     該方法首先呼叫該執行緒的checkAccess方法,不帶任何引數,可能丟擲SecurityException(在當前執行緒中)。
 3     
 4     引數:
 5         on-如果為true,則將該執行緒標記為守護執行緒。
 6     丟擲:
 7         IllegalThreadStateException-如果該執行緒處於活動狀態。
 8         SecrurityException-如果當前無法修改該執行緒。
 9     另請參見:
10         isDaemon(),checkAccess()

  具體例子:當最後只剩下守護執行緒在執行時,JVM退出。

  DaemonTest.java

 1 package Thread;
 2 public class PriorityTest {
 3     public static void main(String[] args){
 4         Thread t1=new MyThread_2();
 5         Thread t2=new Thread(new MyRunnable2());
 6         t2.setDaemon(true);//設定為守護執行緒
 7         t2.start();
 8         t1.start();
 9         
10     }
11 }
12 class MyThread_2 extends Thread{
13     public void run(){
14         for(int i=0;i<5;i++){
15             System.out.println("執行緒1第"+i+"次執行!");
16             try{
17                 Thread.sleep(7);//影響的是執行速度。
18             }catch(InterruptedException e){
19                 e.printStackTrace();
20             }
21         }
22     }
23 }
24 class MyRunnable2 implements Runnable{
25     public void run(){
26         for(int i=0;i<99999L;i++){
27             System.out.println("執行緒2第"+i+"次執行!");
28             try{
29                 Thread.sleep(7);
30             }catch(InterruptedException e){
31                 e.printStackTrace();
32             }
33         }
34     }
35 }
View Code

  結果為:

 1 執行緒2第0次執行!
 2 執行緒1第0次執行!
 3 執行緒1第1次執行!
 4 執行緒2第1次執行!
 5 執行緒1第2次執行!
 6 執行緒2第2次執行!
 7 執行緒1第3次執行!
 8 執行緒2第3次執行!
 9 執行緒1第4次執行!
10 執行緒2第4次執行!
11 執行緒2第5次執行!
View Code

四、未捕獲異常處理器

  run方法不能丟擲任何被檢測的異常,但是,不被檢測的異常就會導致執行緒的終止。但是不需要任何catch字句來處理被傳播的異常。相反,死亡之前,異常被傳遞到一個用於未捕獲異常處理器。該處理器實現一個Thread.UncaughtExceptionHandler介面的類。這個介面只有一個方法即:void uncaughtException(Thread t,Throwable e)

  用setUncaughtaExceptionHandler方法為任何執行緒安裝一個處理器。但是如果不為此獨立的執行緒安裝處理器,則ThreadGroup類物件即為此時的處理器。

  ThreadGroup類實現了Thread.UncaughtExceptionHandler介面。它的uncaughtException方法做如下操作:

    1) 如果該執行緒組有父執行緒組,那麼父執行緒組的uncaughtException方法被呼叫。

    2) 否則,如果Thread.getDefaultExceptionHandler方法返回一個非空的處理器,則呼叫該處理器。

    3) 否則,如果Throwable是ThreadDeath的一個例項,什麼都不做。

    4) 否則,執行緒的名字以及Throwable的棧軌跡被輸出到System.err上。此時可以看到多次的棧軌跡。

五、讓步

  讓步就是使當前執行的執行緒讓出CPU資源,雖然不知道給誰,僅僅是讓出,執行緒狀態回到可執行狀態。其中讓步使用Thread.yield()方法,yield方法為靜態方法,功能是暫停當前執行的執行緒物件,並執行其他執行緒。例子:一個執行緒先讓步,讓另一個執行緒先執行,然後再執行該執行緒。

  YieldTest.java

 1 package Thread;
 2 public class PriorityTest {
 3     public static void main(String[] args){
 4         Thread t1=new MyThread_2();
 5         Thread t2=new Thread(new MyRunnable2());
 6         t2.start();
 7         t1.start();
 8         
 9     }
10 }
11 class MyThread_2 extends Thread{
12     public void run(){
13         for(int i=0;i<10;i++){
14             System.out.println("執行緒1第"+i+"次執行!");
15             /*try{
16                 Thread.sleep(7);//影響的是執行速度。
17             }catch(InterruptedException e){
18                 e.printStackTrace();
19             }*/
20         }
21     }
22 }
23 class MyRunnable2 implements Runnable{
24     public void run(){
25         for(int i=0;i<10;i++){
26             System.out.println("執行緒2第"+i+"次執行!");
27             Thread.yield();
28             /*try{
29                 Thread.sleep(7);
30             }catch(InterruptedException e){
31                 e.printStackTrace();
32             }*/
33         }
34     }
35 }
View Code

  結果為:

 1 執行緒1第0次執行!
 2 執行緒1第1次執行!
 3 執行緒1第2次執行!
 4 執行緒1第3次執行!
 5 執行緒1第4次執行!
 6 執行緒1第5次執行!
 7 執行緒1第6次執行!
 8 執行緒1第7次執行!
 9 執行緒1第8次執行!
10 執行緒1第9次執行!
11 執行緒2第0次執行!
12 執行緒2第1次執行!
13 執行緒2第2次執行!
14 執行緒2第3次執行!
15 執行緒2第4次執行!
16 執行緒2第5次執行!
17 執行緒2第6次執行!
18 執行緒2第7次執行!
19 執行緒2第8次執行!
20 執行緒2第9次執行!
View Code

 六、合併

  合併就是將幾個並行執行緒的執行緒合併為一個單執行緒執行,應用場景就是當一個執行緒等待另一個執行緒執行完畢後才能執行,可以使用join方法。思想是當執行join方法後,主執行緒暫停,轉而執行新加入的執行緒,等到新加入的執行緒執行完畢後,才能繼續執行主執行緒。

1 void join()
2     等待該執行緒終止。
3 void join(long millis)
4     等待該執行緒終止的時間最長為millis
5 void join(long millis,int nanos)
6     等待該執行緒終止的最長時間為millis+nanos納秒

  JoinTest.java

 1 package Thread;
 2 public class PriorityTest {
 3     public static void main(String[] args){
 4         Thread t1=new MyThread_2();
 5         //Thread t2=new Thread(new MyRunnable2());
 6         //t2.start();
 7         t1.start();
 8         for(int i=0;i<20;i++){
 9             System.out.println("主執行緒第"+i+"次執行!");
10             if(i>2)
11                 try{
12                     t1.join();//t1執行緒合併到主執行緒中,主執行緒停止執行過程,轉而執行t1執行緒,直到t1執行完畢後繼續。
13                     //Thread.sleep(7);//影響的是執行速度。
14                 }catch(InterruptedException e){
15                     e.printStackTrace();
16                 }
17         }
18     }
19 }
20 class MyThread_2 extends Thread{
21     public void run(){
22         for(int i=0;i<10;i++){
23             System.out.println("執行緒1第"+i+"次執行!");
24             /*if(i>2)
25                 try{
26                     Thread.sleep(7);//影響的是執行速度。
27                 }catch(InterruptedException e){
28                     e.printStackTrace();
29                 }*/
30         }
31     }
32 }
33 /*class MyRunnable2 implements Runnable{
34     public void run(){
35         for(int i=0;i<10;i++){
36             System.out.println("執行緒2第"+i+"次執行!");
37             Thread.yield();
38             /*try{
39                 Thread.sleep(7);
40             }catch(InterruptedException e){
41                 e.printStackTrace();
42             }
43         }
44     }
45 }*/
View Code

  結果為:

 1 主執行緒第0次執行!
 2 主執行緒第1次執行!
 3 主執行緒第2次執行!
 4 執行緒1第0次執行!
 5 執行緒1第1次執行!
 6 執行緒1第2次執行!
 7 執行緒1第3次執行!
 8 執行緒1第4次執行!
 9 執行緒1第5次執行!
10 執行緒1第6次執行!
11 執行緒1第7次執行!
12 執行緒1第8次執行!
13 執行緒1第9次執行!
14 主執行緒第3次執行!
15 主執行緒第4次執行!
16 主執行緒第5次執行!
17 主執行緒第6次執行!
18 主執行緒第7次執行!
19 主執行緒第8次執行!
20 主執行緒第9次執行!
21 主執行緒第10次執行!
22 主執行緒第11次執行!
23 主執行緒第12次執行!
24 主執行緒第13次執行!
25 主執行緒第14次執行!
26 主執行緒第15次執行!
27 主執行緒第16次執行!
28 主執行緒第17次執行!
29 主執行緒第18次執行!
30 主執行緒第19次執行!
View Code