【Java多線程與併發】——join

目錄

1、join()簡介

2、例子

3、底層原理

4、其他方法


1、join()簡介

join()方法的作用在一個線程內調用另一個線程實例的join()方法,表示線程在此阻塞,以等待相應的實例執行完成,join()內部是通過wait()方法實現的,因此調用join會自動釋放鎖

2、例子

public class ThreadDemo extends Thread {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " begin run");
        long startTime = System.currentTimeMillis();
        try {
            //模擬耗時處理
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println(Thread.currentThread().getName() + "執行時間爲:" + (endTime - startTime));
        System.out.println(Thread.currentThread().getName() + "end run");
    }
}
public class RunTest {

    public static void main(String[] args) throws InterruptedException {
        Thread.currentThread().setName("主線程");
        System.out.println(Thread.currentThread().getName() + "begin run");
        ThreadDemo threadDemo = new ThreadDemo();
        threadDemo.setName("子線程");
        threadDemo.start();
        //阻塞等待
        threadDemo.join();
        System.out.println(Thread.currentThread().getName() + "end run");
    }

}

 運行結果:

從結果中我們可以看出,主線程調用子線程,當執行到join()方法時,子線程對象進入阻塞隊列,待子線程執行完畢後主線程繼續執行。

3、底層原理

join()方法源碼:

    public final void join() throws InterruptedException {
        join(0);
    }

    public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;
        
        if (millis < 0) {//若millis小於0則拋出異常
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {//若millis=0
            while (isAlive()) {//判斷當前線程是否存活
                wait(0);//永久等待,直到線程銷燬
            }
        } else {//millis大於0,阻塞指定時間,若時間過期,線程還未結束,就不等待了
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

從源碼可知,當參數millis爲0時,while循環使用isAlive()方法判斷當前線程是否存活(線程存活是指線程已經啓動並且還沒有死亡),wait(0)表示永遠等待。

注意,我們在源碼中看到只有wait()方法,卻沒看到notify()方法,那麼是由誰去喚醒在阻塞池中的線程呢?這個是在jvm中實現的, 一個線程執行結束後會執行該線程自身對象的notifyAll方法。

4、其他方法

  • join(long millis):等待執行毫秒,到時後就不等待了
    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(long millis, int nanos):等待最多爲millis+1毫秒,最少爲1毫秒
    public final synchronized void join(long millis, int nanos)
    throws InterruptedException {

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
            //當nanos大於500微妙時,或者毫秒值=0,則等待時間爲millis+1毫秒值,至少爲1毫秒
            millis++;
        }

        join(millis);
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章