1. 程式人生 > >java多執行緒中對於join方法的理解

java多執行緒中對於join方法的理解

對於多執行緒的join方法一直理解得很模糊,大致看了一些資料,JDK是這樣說的:join public final void join (long millis )throws InterruptedException Waits at most millis milliseconds for this thread to die. A timeout of 0 means to wait forever. 字面意思是join用於主執行緒等待子執行緒執行完畢它的run方法,再繼續執行下面的程式碼。例如:

public class JoinTest {

    public static
void main(String[] args) { Thread t = new Thread( new RunnableImpl()); t.start(); try { t.join();//t執行緒完成run方法後才會繼續執行下面的程式碼! } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } Thread t1 = new
Thread( new RunnableImpl1()); t1.start(); }

就是說如果是t.join() = t.join(0) JDK 這樣說的 A timeout of 0 means to wait forever 字面意思是永遠等待,其實是等到t 結束後。

JDK原始碼如下:

public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long
now = 0; if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }

其實Join 方法實現是通過wait (小提示:Object 提供的方法)。 當main 執行緒呼叫t.join 時候,main 執行緒會獲得執行緒物件t 的鎖 (wait 意味著拿到該物件的鎖), 呼叫該物件的wait( 等待時間) ,直到該物件喚醒main 執行緒,比如退出後。
這就意味著main 執行緒呼叫t.join 時,必須能夠拿到執行緒t 物件的鎖 ,如果拿不到它是無法wait 的,剛開的例子t.join(1000) 不是說明了main 執行緒等待1 秒,如果在它等待之前,其他執行緒獲取了t 物件的鎖,它等待時間可不就是1 毫秒了。上程式碼介紹:

public   class  JoinTest { 
    public   static   void  main(String[] args) { 
    Thread t =  new  Thread( new  RunnableImpl()); 
    new  ThreadTest(t).start();// 這個執行緒會持有鎖 
    t.start(); 
    try  { 
    t.join(); 
    System.out.println("joinFinish"); 
    }  catch  (InterruptedException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
    } 
    } 
    } 
    class  ThreadTest  extends  Thread { 
    Thread thread; 
    public  ThreadTest(Thread thread) { 
    this .thread = thread; 
    } 
    @Override 
    public   void  run() { 
    holdThreadLock(); 
    } 
    public   void  holdThreadLock() { 
    synchronized  (thread) { 
    System.out.println("getObjectLock"); 
    try  { 
    Thread.sleep(9000); 
    }  catch  (InterruptedException ex) { 
    ex.printStackTrace(); 
    } 
    System.out.println("ReleaseObjectLock"); 
    } 
    } 
    } 
    class  RunnableImpl  implements  Runnable { 
    @Override 
    public   void  run() { 
    try  { 
    System.out.println("Begin sleep"); 
    Thread.sleep(2000); 
    System.out.println("End sleep"); 
    }  catch  (InterruptedException e) { 
    e.printStackTrace(); 
    } 
    } 
    } 

在main 方法中 通過new ThreadTest(t).start(); 例項化ThreadTest 執行緒物件, 它在 holdThreadLock() 方法中,通過 synchronized (thread) ,獲取執行緒物件t 的鎖,並Sleep (9000 )後釋放,這就意味著,即使
main 方法t.join(1000), 等待一秒鐘,它必須等待 ThreadTest 執行緒釋放t 鎖後才能進入wait 方法中,它實際等待時間是9000+1000 MS

執行結果是:
getObjectLock
Begin sleep
End sleep
ReleaseObjectLock
joinFinish