一、線程與進程 1、進程是程式(任務)執行過程,持有資源(共用記憶體,共用檔案)和線程,進程是動態性的,如果程式沒有執行就不算一個進程。
2、線程是系統中最小的執行單元,同一進程中有多個線程,線程共用進程的資源
Java中建立現成的方式就不再贅述了,有兩種:(1)繼承Thread類,重寫run()方法,(2)實現Runnable介面,重寫run()方法。
二、yield()方法
在jdk文檔中,yield()方法是這樣描述的:暫停當前正在執行的線程對象,並執行其他線程。在多線程的情況下,由CPU決定執行哪一個線程,而yield()方法就是暫停當前的線程,讓給其他線程(包括它自己)執行,具體由誰執行由CPU決定。 yield()方法執行個體
YieldRunnable.java
public class YieldRunnable implements Runnable{public volatile boolean isRunning = true;@Overridepublic void run() {String name = Thread.currentThread().getName();System.out.println(name + "開始執行。");while(isRunning) {for(int i = 1; i < 6; i++) {System.out.println(name + "執行了[" + i + "]次");//注意,yield是靜態方法Thread.yield();}}System.out.println(name + "執行結束。");}}執行的main函數
public static void main(String[] args) {YieldRunnable runnable1 = new YieldRunnable();YieldRunnable runnable2 = new YieldRunnable();Thread thread1 = new Thread(runnable1, "線程1");Thread thread2 = new Thread(runnable2, "線程2"); System.out.println("兩個線程準備開始執行");thread1.start();thread2.start();try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}runnable1.isRunning = false;runnable2.isRunning = false;}選取部分執行結果分析:
1、第一種情況:
……
線程1執行了[1]次
線程2執行了[1]次
線程2執行了[2]次
線程2執行了[3]次
線程2執行了[4]次
線程1執行了[2]次
……
從這個執行結果可以看出,線程1在執行了一次之後,讓出執行權,CPU將執行權給了線程2,線程2執行了一次之後讓出執行權,但是CPU仍將執行權給2,就這樣線程2反覆執行了幾次,CPU一直都是將執行權給線程2,知道線程2執行完第4次之後,CPU才將執行權給線程1。
2、第二種情況:
……
線程1執行了[1]次
線程2執行了[3]次
線程1執行了[2]次
線程2執行了[4]次
線程1執行了[3]次
線程2執行了[5]次
……
從這個執行結果可以看出,線程1執行一次後,讓出執行權,CPU將執行權給了線程2,線程2執行一次後,CPU將執行權又給了1,就這樣交替執行了幾次線程1和線程2。
從上面兩種執行結果來看,一個線程執行yield()方法暫停後,CPU決定接下來有哪一個線程執行,可以是其他線程,也可以是原來的那個線程。
三、join()方法 join()方法是指等待調用join()方法的線程執行結束,程式才會繼續執行下去,這個方法適用於:一個執行程式必須等待另一個線程的執行結果才能夠繼續啟動並執行情況。 join()方法執行個體 定義一個線程: JoinRunnable.java
public class JoinRunnable implements Runnable {@Overridepublic void run() {String name = Thread.currentThread().getName();System.out.println(name + "開始執行。");for(int i = 1; i < 6; i++) {System.out.println(name + "執行了[" + i + "]次");}}}
先來看一下沒有使用join()方法的情況:
public static void main(String[] args) {JoinRunnable runnable1 = new JoinRunnable();Thread thread1 = new Thread(runnable1, "線程1");System.out.println("主線程開始執行。");thread1.start();System.out.println("主線程執行結束。");}執行結果: 主線程開始執行。
主線程執行結束。
線程1開始執行。
線程1執行了[1]次
線程1執行了[2]次
線程1執行了[3]次
線程1執行了[4]次
線程1執行了[5]次
從執行結果可以看出,如果沒有使用join方法,那麼main方法所在的線程(暫訂叫主線程)在啟動了JoinRunnable線程(暫訂叫子線程)之後,沒有等待子線程執行結束,就先執行結束了。
如果使用了join方法:
public static void main(String[] args) {JoinRunnable runnable1 = new JoinRunnable();Thread thread1 = new Thread(runnable1, "線程1");System.out.println("主線程開始執行。");thread1.start();try {thread1.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("主線程執行結束。");}執行結果: 主線程開始執行。
線程1開始執行。
線程1執行了[1]次
線程1執行了[2]次
線程1執行了[3]次
線程1執行了[4]次
線程1執行了[5]次
主線程執行結束。
從執行結果可以看出,加入join()方法,主線程啟動了子線程之後,在等待子線程執行完畢才繼續執行下面的操作。
注意:join()方法只有在start()方法之後才可以生效。可以參考下面的代碼,將join()方法寫在start()方法之前。
public static void main(String[] args) {JoinRunnable runnable1 = new JoinRunnable();Thread thread1 = new Thread(runnable1, "線程1");System.out.println("主線程開始執行。");try {thread1.join();} catch (InterruptedException e) {e.printStackTrace();}thread1.start();System.out.println("主線程執行結束。");}執行結果: 主線程開始執行。
主線程執行結束。
線程1開始執行。
線程1執行了[1]次
線程1執行了[2]次
線程1執行了[3]次
線程1執行了[4]次
線程1執行了[5]次
雖然加入了join()方法,但是是線上程啟動的start()方法之前調用的,所以join()方法不生效。具體原因可以參考一下源碼
public final void join() throws InterruptedException { join(0L); } public final synchronized void join(long l) throws InterruptedException { long l1 = System.currentTimeMillis(); long l2 = 0L; if(l < 0L) throw new IllegalArgumentException("timeout value is negative"); if(l == 0L) for(; isAlive(); wait(0L));//isAlive()是判斷當前線程的狀態,wait(0)是指等待直到線程結束 else do { if(!isAlive()) break; long l3 = l - l2; if(l3 <= 0L) break; wait(l3); l2 = System.currentTimeMillis() - l1; } while(true); }從源碼可以看出,join()方法調用了join(long l)方法,參數l的值為0,之後在判斷中如果l的值為0,則執行一個迴圈,迴圈執行的條件為當前線程是否isAlive(),就是指線程是否已經運行,如果線程未啟動(即未調用start方法),則迴圈條件不成立,直接退出,也就是說join()方法不生效。 在看這裡的源碼的時候發現了一個小問題,對於isAlive()和wait()方法的作用對象是有點讓人疑惑的,isAlive()判斷當前線程的狀態,還好理解,在上面的例子中就是指thread1。但是wait()方法的作用對象到底是誰,產生了疑問,按照jdk的說法等待的應該是當前線程,那就是thread1,但是實際運行中,等待的是主線程,有點讓人摸不著頭腦。之後在網上找到 這篇文章,裡面說當我們在synchronized塊 中調用鎖對象的wait()方法,那麼調用線程就會阻塞在wait()語句那裡,直到其他線程調用線程的notify()方法。這裡的調用線程也就是指主線程,因為wai()方法是在Thread類中的synchronized方法join(long l)中調用的,所以主線程阻塞,直到線程執行完畢調用了notify()方法才繼續執行,這個說法先記錄一下,以備以後考證。
最後一點小插曲: 在編碼的時候嘗試過在start()方法和join()方法之間加入一些內容,也就是說調用start()方法啟動線程之後不立即調用join()方法,想看一下是否出現:先啟動子線程,執行相關操作,然後再執行主線程中的內容,再等待子線程執行結束的情況。範例程式碼:
public static void main(String[] args) {JoinRunnable runnable1 = new JoinRunnable();Thread thread1 = new Thread(runnable1, "線程1");System.out.println("主線程開始執行。");thread1.start();//啟動子線程之後主線程休眠1秒<span style="white-space:pre"></span>try {Thread.sleep(1000);} catch (InterruptedException e1) {e1.printStackTrace();}try {thread1.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("主線程執行結束。");}執行結果: 主線程開始執行。
線程1開始執行。
線程1執行了[1]次
線程1執行了[2]次
線程1執行了[3]次
線程1執行了[4]次
線程1執行了[5]次
主線程執行結束。
實際執行的時候主線程休眠1秒是在子線程執行結束之後才執行的,由此可以推斷,只要在start()方法之後調用了join()方法,不管這兩個方法之間加入多少內容,主線程都會優先等待子線程執行結束才會繼續往下執行。