日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

java 线程执行结束_Java_如何等待子线程执行结束

發(fā)布時(shí)間:2023/12/10 java 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 线程执行结束_Java_如何等待子线程执行结束 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本程序的數(shù)據(jù)有可能是如下:

main thread work start

sub thread start working.

main thread work done.

now waiting sub thread done.

sub thread stop working.

now all done.

忽略標(biāo)號(hào), 當(dāng)然輸出也有可能是1和2調(diào)換位置了. 這個(gè)我們是無(wú)法控制的. 我們看下線程的join操作, 究竟干了什么.

這里是調(diào)用了

public?final?synchronized?void?join(long?millis)

方法, 參數(shù)為0, 表示沒(méi)有超時(shí)時(shí)間, 等到線程結(jié)束為止. join(millis)方法里面有這么一段代碼:

說(shuō)明, 當(dāng)線程處于活躍狀態(tài)的時(shí)候, 會(huì)一直等待, 直到這里的isAlive方法返回false, 才會(huì)結(jié)束.isAlive方法是一個(gè)本地方法, 他的作用是判斷線程是否已經(jīng)執(zhí)行結(jié)束. 注釋是這么寫(xiě)的:

Tests if this thread is alive. A thread is alive if it has?been started and has not yet died.

可見(jiàn), join系列方法可以幫助我們等待一個(gè)子線程的結(jié)束.

那么要問(wèn), 有沒(méi)有另外一種方法可以等待子線程結(jié)束? 當(dāng)然有的, 我們可以使用并發(fā)包下面的Future模式.

Future是一個(gè)任務(wù)執(zhí)行的結(jié)果, 他是一個(gè)將來(lái)時(shí), 即一個(gè)任務(wù)執(zhí)行, 立即異步返回一個(gè)Future對(duì)象, 等到任務(wù)結(jié)束的時(shí)候, 會(huì)把值返回給這個(gè)future對(duì)象里面. 我們可以使用ExecutorService接口來(lái)提交一個(gè)線程.

這里, ThreadPoolExecutor 是實(shí)現(xiàn)了 ExecutorService的方法, sumbit的過(guò)程就是把一個(gè)Runnable接口對(duì)象包裝成一個(gè) Callable接口對(duì)象, 然后放到 workQueue里等待調(diào)度執(zhí)行. 當(dāng)然, 執(zhí)行的啟動(dòng)也是調(diào)用了thread的start來(lái)做到的, 只不過(guò)這里被包裝掉了. 另外, 這里的thread是會(huì)被重復(fù)利用的, 所以這里要退出主線程, 需要執(zhí)行以下shutdown方法以示退出使用線程池. 扯遠(yuǎn)了.

這種方法是得益于Callable接口和Future模式, 調(diào)用future接口的get方法, 會(huì)同步等待該future執(zhí)行結(jié)束, 然后獲取到結(jié)果. Callbale接口的接口方法是 V call(); 是可以有返回結(jié)果的, 而Runnable的 void run(), 是沒(méi)有返回結(jié)果的. 所以, 這里即使被包裝成Callbale接口, future.get返回的結(jié)果也是null的.如果需要得到返回結(jié)果, 建議使用Callable接口.

通過(guò)隊(duì)列來(lái)控制線程的進(jìn)度, 是很好的一個(gè)理念. 我們完全可以自己搞個(gè)隊(duì)列, 自己控制. 這樣也可以實(shí)現(xiàn). 不信看代碼:

這里是得益于我們用了一個(gè)阻塞隊(duì)列, 他的put操作和take操作都會(huì)阻塞(同步), 在滿足條件的情況下.當(dāng)我們調(diào)用take()方法時(shí), 由于子線程還沒(méi)結(jié)束, 隊(duì)列是空的, 所以這里的take操作會(huì)阻塞, 直到子線程結(jié)束的時(shí)候, 往隊(duì)列里面put了個(gè)元素, 表明自己結(jié)束了. 這時(shí)候主線程的take()就會(huì)返回他拿到的數(shù)據(jù). 當(dāng)然, 他拿到什么我們是不必去關(guān)心的.

以上幾種情況都是針對(duì)子線程只有1個(gè)的時(shí)候. 當(dāng)子線程有多個(gè)的時(shí)候, 情況就不妙了.

第一種方法, 你要調(diào)用很多個(gè)線程的join, 特別是當(dāng)你的線程不是for循環(huán)創(chuàng)建的, 而是一個(gè)一個(gè)創(chuàng)建的時(shí)候.

第二種方法, 要調(diào)用很多的future的get方法, 同第一種方法.

第三種方法, 比較方便一些, 只需要每個(gè)線程都在queue里面 put一個(gè)元素就好了.但是, 第三種方法, 這個(gè)隊(duì)列里的對(duì)象, 對(duì)我們是毫無(wú)用處, 我們?yōu)榱耸褂藐?duì)列, 而要不明不白浪費(fèi)一些內(nèi)存, 那有沒(méi)有更好的辦法呢?

有的, concurrency包里面提供了好多有用的東東, 其中, CountDownLanch就是我們要用的.

CountDownLanch 是一個(gè)倒數(shù)計(jì)數(shù)器, 給一個(gè)初始值(>=0), 然后每countDown一次就會(huì)減1, 這很符合等待多個(gè)子線程結(jié)束的場(chǎng)景: 一個(gè)線程結(jié)束的時(shí)候, countDown一次, 直到所有都countDown了 , 那么所有子線程就都結(jié)束了.

先看看CountDownLanch有哪些方法:

await: 會(huì)阻塞等待計(jì)數(shù)器減少到0位置. 帶參數(shù)的await是多了等待時(shí)間.

countDown: 將當(dāng)前的技術(shù)減1

getCount(): 返回當(dāng)前的計(jì)數(shù)

顯而易見(jiàn), 我們只需要在子線程執(zhí)行之前, 賦予初始化countDownLanch, 并賦予線程數(shù)量為初始值.

每個(gè)線程執(zhí)行完畢的時(shí)候, 就countDown一下.主線程只需要調(diào)用await方法, 可以等待所有子線程執(zhí)行結(jié)束, 看代碼:

此種方法也適用于使用 ExecutorService summit 的任務(wù)的執(zhí)行.

另外還有一個(gè)并發(fā)包的類CyclicBarrier, 這個(gè)是(子)線程之間的互相等待的利器. 柵欄, 就是把大家都在一個(gè)地方堵住, 就像水閘, 等大家都完成了之前的操作, 在一起繼續(xù)下面的操作. 不過(guò)就不再本篇的討論范圍內(nèi)了.

EOF

總結(jié)

以上是生活随笔為你收集整理的java 线程执行结束_Java_如何等待子线程执行结束的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。