溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java中join有什么用

發(fā)布時(shí)間:2021-12-14 16:12:14 來(lái)源:億速云 閱讀:291 作者:小新 欄目:開(kāi)發(fā)技術(shù)

小編給大家分享一下Java中join有什么用,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

java多線程里的join,從字面意思來(lái)看是聯(lián)合,合并的意思,但如果面試時(shí)這么回答,基本上可以斷定面試者還沒(méi)搞懂。join究竟能干什么,今天給出一個(gè)最通俗的解釋?zhuān)蔷褪窃诙嗑€程環(huán)境下實(shí)現(xiàn)暫時(shí)以單線程執(zhí)行,或者說(shuō)在并行執(zhí)行的環(huán)境中實(shí)現(xiàn)暫時(shí)以串行執(zhí)行。為了說(shuō)明這個(gè)問(wèn)題,我們看一段再常見(jiàn)不過(guò)的代碼,代碼內(nèi)容是,讓三個(gè)線程分布去打印一段內(nèi)容

//代碼塊1
public class TestJoin {
   public static void main(String[] args) throws InterruptedException {
       Thread t1 = new Thread(new DoSth());
       Thread t2 = new Thread(new DoSth());
       Thread t3 = new Thread(new DoSth());
       t1.start();
       t2.start();
       t3.start();
       System.out.println("主線程執(zhí)行");
   }
}

class DoSth implements Runnable {
   @Override
   public void run() {
       int n = 5;
       while (n > 0) {
           System.out.println(Thread.currentThread().getName());
           try {
               Thread.sleep(1);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           n--;
       }
   }
}

執(zhí)行結(jié)果如下:

線程1執(zhí)行
線程2執(zhí)行
線程3執(zhí)行
線程2執(zhí)行
線程3執(zhí)行
線程1執(zhí)行
線程2執(zhí)行
線程3執(zhí)行
線程2執(zhí)行
線程3執(zhí)行
線程2執(zhí)行
線程3執(zhí)行
線程1執(zhí)行
線程1執(zhí)行
線程1執(zhí)行

可見(jiàn)三個(gè)線程各自并行執(zhí)行,并無(wú)明確的先后順序。但如果我們?cè)趖.start()后面加上這行代碼,

//代碼塊2
t1.start();
t1.join();

看會(huì)出現(xiàn)看什么樣的結(jié)果:

線程1執(zhí)行
線程1執(zhí)行
線程1執(zhí)行
線程1執(zhí)行
線程1執(zhí)行
線程2執(zhí)行
線程3執(zhí)行
線程3執(zhí)行
線程2執(zhí)行
線程3執(zhí)行
線程2執(zhí)行
線程3執(zhí)行
線程2執(zhí)行
線程3執(zhí)行
線程2執(zhí)行

可以看到線程1執(zhí)行結(jié)束之后線程2和3才開(kāi)始執(zhí)行,可見(jiàn)在線程1執(zhí)行過(guò)程中,其他線程并未執(zhí)行,線程1結(jié)束后,線程2,線程3開(kāi)始并行執(zhí)行,這就印證了前面的結(jié)論,即:join的作用是在多線程環(huán)境下暫時(shí)以單線程執(zhí)行。明白了這一點(diǎn),接下來(lái)的問(wèn)題是,這個(gè)特性是怎么實(shí)現(xiàn)的呢?我們跟到源碼:可以看到

//代碼塊3

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;
   }
}

}

在第12行調(diào)用了wait,注意這里的wait,它并不是指線程線程1對(duì)象執(zhí)行wait,而是線程1的調(diào)用者,也就是相當(dāng)于在主線程去執(zhí)行wait,可等價(jià)理解為以下偽代碼:

t1.start();
while(t1.isAlive()){
   Thread.currentThread().doWait()
}

此時(shí)執(zhí)行流程會(huì)在代碼塊3的11-13行循環(huán)執(zhí)行,當(dāng)線程1執(zhí)行完畢時(shí),其生命周期結(jié)束,isAlive()返回false,11-13行退出循環(huán),繼續(xù)執(zhí)行下面的代碼,此時(shí)又切換為并行執(zhí)行狀態(tài)。對(duì)于以上執(zhí)行效果,我們完全可以不用創(chuàng)建t1線程,而是把在主線程中直接去調(diào)用t1的核心邏輯,代碼如下:

public static void main(String[] args) throws InterruptedException {
   //Thread t1 = new Thread(new DoSth(), "線程1");
   Thread t2 = new Thread(new DoSth(), "線程2");
   Thread t3 = new Thread(new DoSth(), "線程3");
   //t1.start();
   //t1.join();
   new DoSth().run();//直接調(diào)用業(yè)務(wù)邏輯,而不是分配線程去執(zhí)行
   t2.start();
   t3.start();
   System.out.println("主線程執(zhí)行");
}

和之前的代碼相比,本來(lái)需要在子線程t1中執(zhí)行的內(nèi)容,通過(guò)在主線程中執(zhí)行達(dá)到了相同的效果,而這種特性,就體現(xiàn)了所謂的join,現(xiàn)在你明白為什么叫join了吧?join在實(shí)際應(yīng)用當(dāng)中有什么用呢?把以上代碼改造一下,用一個(gè)例子來(lái)說(shuō)明。

public static void main(String[] args) throws InterruptedException {
   Thread t1 = new Thread(new DoSth(), "小組1");
   Thread t2 = new Thread(new DoSth(), "小組2");
   Thread t3 = new Thread(new DoSth(), "小組3");
   t1.start();
   t2.start();
   t3.start();
   t1.join();
   t2.join();
   t3.join();
   System.out.println("集合完畢");
}

執(zhí)行結(jié)果:

小組3正在集合
小組1正在集合
小組2正在集合
小組3正在集合
小組1正在集合
小組2正在集合
小組3正在集合
小組1正在集合
集合完畢

當(dāng)我們需要多個(gè)子線程分布去完成各自的任務(wù),并在這些子線程全部完成后,主線程做統(tǒng)一匯總時(shí),join就派上用場(chǎng)了。不過(guò)細(xì)心的讀者會(huì)發(fā)現(xiàn),這些子線程并未返回任何結(jié)果,如果我們需要返回結(jié)果供主線程使用時(shí),該怎么實(shí)現(xiàn),針對(duì)這一需求,單靠實(shí)現(xiàn)Runnable的方式已經(jīng)無(wú)法做到了,此時(shí)需要用到另外的接口:Feature和Callable。

以上是“Java中join有什么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI