一、Java的優先級
Java提供了一個線程調度器來監控程序啟動后進去就緒狀態的所有線程。線程調度器通過線程的優先級來決定調度哪些線程執行。一般來說,Java的線程調度器采用時間片輪轉算法使多個線程輪轉獲得CPU的時間片。然而根據實際情況,每個線程的重要程序也不相同,有時候我們想讓一些線程優先執行,那么我們可以將他的優先級調高一下,這樣它們獲得的時間片會多一些。
多個線程處於就緒狀態時,若這些線程的優先級相同,則線程調度器會按時間片輪轉方式或獨占方式來分配線程的執行時間。
Java中線程優先級用1~10來表示,分為三個級別:
低優先級:1~4,其中類變量Thread.MIN_PRORITY最低,數值為1;
默認優先級:如果一個線程沒有指定優先級,默認優先級為5,由類變量Thread.NORM_PRORITY表示;
高優先級:6~10,類變量Thread.MAX_PRORITY最高,數值為10。
注意:具有相同優先級的多個線程,若它們都為高優先級Thread.MAX_PRORITY,則每個線程都是獨占式的,也就是這些線程將被順序執行;
若它們優先級不是高優先級,則這些線程將被同時執行,可以說是無序執行。
public class PriorityDemo extends Thread { public PriorityDemo(String name) { super(name); } @Override public void run() { for (int i=1;i<4;i++){ System.out.println(this.getName() + "循環了:" + i + "次"); } } } public class PriorityDriver { public static void main(String[] args) { System.out.println("當前線程位:" + Thread.currentThread().getName() + ",優先級為:" + Thread.currentThread().getPriority()); PriorityDemo thread1 = new PriorityDemo("thread1"); PriorityDemo thread2 = new PriorityDemo("thread2"); PriorityDemo thread3 = new PriorityDemo("thread3"); thread1.setPriority(MIN_PRIORITY); thread3.setPriority(MAX_PRIORITY); thread1.start(); thread2.start();
thread3.start(); } }
運行結果如下:由結果可以看出,不是高優先級的線程就一定先比低優先級執行完,而是高優先級線程先執行的概率比低優先級的線程高。
二、isAlive()方法
isAlive()方法用來判斷線程目前是否正在執行,可以用來判斷線程是否執行完畢。
如果線程已被啟動並且未被終止,則返回true,但是沒有進一步判斷線程是可運行的或是阻塞的;
如果線程是新創建的或已被終止的,則返回false。
public class IsAliveDemo extends Thread { public IsAliveDemo(String name) { super(name); } @Override public void run() { for (int i=1;i<4;i++){ System.out.println(Thread.currentThread().getName() + "循環了" + i + "次"); } } } public class IsAliveDriver { public static void main(String[] args) { IsAliveDemo thread1 = new IsAliveDemo("thread1"); IsAliveDemo thread2 = new IsAliveDemo("thread2"); thread1.start(); System.out.println("當前線程對象為:" + Thread.currentThread().getName()); System.out.println("線程thread1是否處於活動狀態?" + thread1.isAlive()); System.out.println("線程thread2是否處於活動狀態?" + thread2.isAlive()); } }
結果如下:
三、yield()方法
yield()方法是Thread的類的類方法,它的作用是將當前正在執行的線程暫停並放置就緒線程隊列最后,讓Java線程調度器重新調度處於就緒狀態的線程,若隊列為空(處於就緒狀態的線程僅有一個),則yield方法無效。
一般來說,重新調度之后與被暫停線程優先級相同的或比它優先級高的線程對象獲取CPU使用權的可能性較大,但也有可能重新調度的仍是被暫停的同一個線程對象。
public class YieldDemo extends Thread { public YieldDemo(String name) { super(name); } @Override public void run() { for (int i=1;i<11;i++){ System.out.println(this.currentThread().getName() + "循環了" + i + "次"); if (i == 5){ //暫停當前正在執行的線程,讓CPU重新調度 this.currentThread().yield(); } } } } public class YieldDriver { public static void main(String[] args) { //創建三個Yield線程對象 YieldDemo thread1 = new YieldDemo("thread1"); YieldDemo thread2 = new YieldDemo("thread2"); YieldDemo thread3 = new YieldDemo("thread3"); //設置它們的優先級 thread1.setPriority(Thread.MIN_PRIORITY); thread2.setPriority(Thread.NORM_PRIORITY); thread3.setPriority(Thread.MAX_PRIORITY); //啟動三個線程對象 thread1.start(); thread2.start(); thread3.start(); } }
四、join()方法
join()方法的作用是等待調用join方法的線程執行完畢,再執行其他線程。
如果當前正在執行線程對象T1,再T1的執行流中調用了線程對象T2的join()方法,那么線程T1將處於阻塞狀態直到線程T2執行完畢為止。
join()方法還有一種形式,“join(long t)”,該方法的參數t為等待時間,作用是等待當前加入的線程對象執行t毫秒,如果等待時間過去了,那么進入阻塞狀態的線程就不再等待加入的線程對象。
public class JoinDemo extends Thread { public JoinDemo(String name) { super(name); } @Override public void run() { System.out.println("開始執行" + Thread.currentThread().getName() + "線程"); for (int i=1;i<6;i++){ System.out.println(this.getName() + "運行了" + i + "次"); } System.out.println(Thread.currentThread().getName() + "線程執行完畢!"); } } public class JoinDriver { public static void main(String[] args) { System.out.println("當前執行線程為:" + Thread.currentThread().getName()); //實例化線程1#並啟動 new JoinDemo("1#").start(); for (int j=1;j<11;j++){ if (j == 5){ JoinDemo jd = new JoinDemo(j + "#"); jd.start(); try { jd.join(); } catch (InterruptedException e) { e.printStackTrace(); } } } //實例化線程2#並啟動 new JoinDemo("2#").start(); } }
運行結果如下:由結果可知,在多核CPU下,線程1#和5#會搶奪CPU使用權,但是線程2#是無法與5#搶占CPU的時間片的。
join()方法可以用於當主線程(例子中的main)處理完其他事物后,需要用到子線程(例子中的1#、2#、5#)的處理結果才能繼續做后續工作時,這是就可以用到join()方法。
五、interrupt()方法
interrupt()用於中斷一個正在運行的線程對象;
interrupted()用於判斷一個線程對象是否處於中斷狀態,若處於中斷狀態則清除中斷狀態,它是類方法。
isinterrupted()用於判斷一個線程對象是否處於中斷狀態。
public class InterruptDemo extends Thread { private double d = 0.0; public InterruptDemo(String name) { super(name); } @Override public void run() { try { while (!Thread.interrupted()){ System.out.println("I 'm running!"); //讓線程休眠20毫秒 Thread.sleep(20); System.out.println("Calculating..."); for (int i=0;i<1000;i++){ d = d + (Math.PI + Math.E)/d; } } } catch (InterruptedException e) { System.out.println("Exiting by Exception"); } System.out.println("run() of " + Thread.currentThread().getName() +" is interrupted!"); } } public class InterruptDriver { public static void main(String[] args) throws InterruptedException { //創建線程對象 InterruptDemo thread1 = new InterruptDemo("thread1"); thread1.start(); Thread.sleep(100); System.out.println("當前線程為" + Thread.currentThread().getName()); System.out.println("**********************"); System.out.println("Interrupted Thread!"); System.out.println("**********************"); thread1.interrupt(); } }
結果如下:在main方法中,初始化了thread1線程對象並啟動了它,然后讓主線程休眠100毫秒,thread1線程對象獲取CPU使用權,運行InterruptDemo的run方法,“!Thread.interrupted()”為true,執行while循環中的邏輯,當主線程結束休眠,開始運行main方法中的邏輯。該例子把interrupt()和interrupt()方法結合使用,從而可以正常的中斷程序的運行。
注意:(1)最后thread1線程對象不是通過interrupt()方法中斷的,而是thread線程run()方法中調用了Thread.sleep(20)方法后,thread.interrupt()生效,然后while循環中判斷條件“!Thread.interrupted()”為false,然后結束了線程。
(2)interrupt()方法不會直接中斷一個正在運行的線程對象,而是在線程被阻塞時拋出一個中斷信號,這樣線程就得以退出阻塞狀態。更具體一點,如果線程對象被wait()、join()、sleep()三種方法的任意一種阻塞,那么該線程對象將接受到一個中斷異常,從而提前終結阻塞狀態。如果線程沒有被阻塞,調用interrupt()方法將不起作用。