Thread.join()方法實現main()方法等待所有子執行緒執行完成[base jdk8]

FeelTouch發表於2018-02-03

程式碼實現

/**
 * Created by Administrator on 2018/2/3.
 */
public class JoinTest {

    public static void main(String[] args) {
        Thread t1 = new Thread(new MyRunnable(), "t1");
        Thread t2 = new Thread(new MyRunnable(), "t2");
        Thread t3 = new Thread(new MyRunnable(), "t3");

        t1.start();
        /**
         * start second thread after waiting for 2 seconds or if it's finished
         */
        try {
            /**
             * main thread wait 2000ms for wait t1 execute finished
             */
            t1.join(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        t2.start();
        /**
         * start third thread only when first thread is finished
         * t.join() = t.join(0) JDK: A timeout of 0 means to wait forever 意思是永遠等待,其實是等到t結束後
         */
        try {
            /**
             * main thread wait t1 execute finished forever
             */
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        t3.start();
        /**
         * let all threads finish execution before finishing main thread
         */
        try {
            /**
             * main thread wait t2 execute finished forever
             */
            t2.join();
            /**
             * main thread wait t3 execute finished forever
             */
            t3.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("All threads are dead, exiting main thread");
    }
}

class MyRunnable implements Runnable {

    @Override
    public void run() {
        System.out.println("Thread started:::" + Thread.currentThread().getName());
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Thread ended:::" + Thread.currentThread().getName());
    }
}

關鍵剖析

Join可以實現執行緒的執行順序,內部具體實現流程分析
try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
    }
	
	public final void join() throws InterruptedException {
        join(0);
    }
	
	/**
	* synchronized修飾,獲得鎖
	*/
	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;
                }
				/**
				* 呼叫Object的wait()方法會釋放鎖
				*/
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }
通過不斷輪詢的方式去觀察執行緒是否還是活動執行緒
join(0)是不斷的詢問執行緒的狀態,直到執行緒銷燬join()方法才會結束。
當millis>0時,不在是wait(0),而是wait(delay),delay是還剩餘的millis時間。有人會問第一次wait(delay)後不就已經經過這millis的時間,
為什麼還會有while執行多次wait(delay)呢?因為這裡不僅要考慮wait在delay時間後被喚醒,還要考慮到在delay時間內,被notify喚醒,喚醒後還沒有執行到millis的時間,因此要多次呼叫wait(delay)方法。 
join方法底層呼叫的是wait方法,但要實現wait的提前是要獲得鎖,執行到wait方法才可以釋放鎖,而sleep方法不釋放鎖。


相關文章