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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【多线程】学习记录七种主线程等待子线程结束之后在执行的方法

發布時間:2025/5/22 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【多线程】学习记录七种主线程等待子线程结束之后在执行的方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近遇到一個問題需要主線程等待所有的子線程結束,才能開始執行,統計所有的子線程執行結果,返回,網上翻閱各種資料,最后記錄一下,找到七種方案

第一種:while循環

對于“等待所有的子線程結束”的問題,最開始想到的是使用while循環進行輪詢:

//開始計時String start = getTheTimeInMilliseconds();System.out.println("start = " + start);Thread t = new Thread(() -> {//子線程進行字符串連接操作int num = 1000;String s = "";for (int i = 0; i < num; i++) {s += "Java" + i;}System.out.println("t Over s =" + s);});t.start();String end = "";//t.getState() != State.TERMINATED這兩種判斷方式都可以while(t.isAlive() == true){end = getTheTimeInMilliseconds();}System.out.println("end = " + end);

但是這樣太消耗CPU,所以我在while循環里加入了暫停,讓其歇會:

while(t.isAlive() == true){end = System.currentTimeMillis();try {Thread.sleep(10);}catch (InterruptedException e){e.printStackTrace();}}

這樣做的結果雖然cpu消耗減少,但是數據不準確了

第二種:Thread的join()方法

將 方法1 中的while循環代碼更改如下

try {t.join();//注意這里} catch (InterruptedException e) {e.printStackTrace();}

使用join()方法,join()方法的作用,是等待這個線程結束;(t.join()方法阻塞調用此方法的線程,直到線程t完成,此線程再繼續)

第三種:synchronized 的等待喚醒機制

第二種方法的確實現了,接著我又想到了多線程的等待喚醒機制,思路是:子線程啟動后主線程等待,子線程結束后喚醒主線程。于是有了下面的代碼:

//開始計時String start = getTheTimeInMilliseconds();System.out.println("start = " + start);Object lock = new Object();Thread t = new Thread(() -> {//子線程進行字符串連接操作int num = 1000;String s = "";for (int i = 0; i < num; i++) {s += "Java" + i;}System.out.println("t Over s =" + s);lock.notify();});t.start();try {lock.wait();//主線程等待} catch (InterruptedException e) {e.printStackTrace();}String end = getTheTimeInMilliseconds();System.out.println("end = " + end);

但是這樣運行結果會拋出兩個異常:

由于對wait()和notify()的理解并不是很深刻,所以我最開始并不清楚為什么會出現這樣的結果,因為從報錯順序來看子線程并沒有提前喚醒,于是我到處翻閱資料,最后得出的結論是調用wait()方法時需要獲取該對象的鎖,Object文檔里是這么說的:

當前線程必須擁有該對象的監視器。如果當前線程不是對象監視器的所有者,拋異常IllegalMonitorStateException。

所以上面的代碼需要改成這樣:

//開始計時String start = getTheTimeInMilliseconds();System.out.println("start = " + start);Object lock = new Object();Thread t = new Thread(() -> {//子線程進行字符串連接操作int num = 1000;String s = "";for (int i = 0; i < num; i++) {s += "Java" + i;}System.out.println("t Over s =" + s);synchronized (lock) {//獲取對象鎖lock.notify();//子線程喚醒}});t.start();try {synchronized (lock) {//這里也是一樣lock.wait();//主線程等待}} catch (InterruptedException e) {e.printStackTrace();}String end = getTheTimeInMilliseconds();System.out.println("end = " + end);

這樣的確得出了結果,但是主線程有可能先wait子線程,在notify,也就是說,如果子線程在主線程wait前,調用了notify,會導致主線程無限等待,所以這個思路還是有一定漏洞的

第四種:CountDownLatch

第四種方式可以等待多個線程結束,就是使用java.util.concurrent包下的CountDownLatch類

簡單來說,CountDownLatch類是一個計數器,可以設置初始線程數(設置后不能改變),在子線程結束時調用countDown()方法可以使線程數減一,最終為0的時候,調用CountDownLatch的成員方法wait()的線程就會取消BLOKED阻塞狀態,進入RUNNABLE從而繼續執行。下面上代碼:

//開始計時String start = getTheTimeInMilliseconds();System.out.println("start = " + start);int threadNumber = 1;//參數為線程個數final CountDownLatch cdl = new CountDownLatch(threadNumber);Thread t = new Thread(() -> {//子線程進行字符串連接操作int num = 1000;String s = "";for (int i = 0; i < num; i++) {s += "Java" + i;}System.out.println("t Over s =" + s);//此方法是CountDownLatch的線程數-1cdl.countDown();});t.start();try {//需要捕獲異常,當其中線程數為0時這里才會繼續運行cdl.await();} catch (InterruptedException e) {e.printStackTrace();}String end = getTheTimeInMilliseconds();System.out.println("end = " + end);

第五種:Future

又想到線程池,線程池的submit()的返回對象Future接口有一個get()方法也可以阻塞當前線程(其實該方法主要用途是獲取子線程的返回值),所以第五種方法也出來了:

//開始計時String start = getTheTimeInMilliseconds();System.out.println("start = " + start);ExecutorService executorService = Executors.newFixedThreadPool(1);Thread t = new Thread(() -> {//子線程進行字符串連接操作int num = 1000;String s = "";for (int i = 0; i < num; i++) {s += "Java" + i;}System.out.println("t Over s =" + s);});//子線程啟動Future future = executorService.submit(t);try {future.get();//需要捕獲兩種異常}catch (InterruptedException e){e.printStackTrace();}catch (ExecutionException e){e.printStackTrace();}String end = getTheTimeInMilliseconds();System.out.println("end = " + end);executorService.shutdown();

這里, ThreadPoolExecutor 是實現了 ExecutorService的方法, sumbit的過程就是把一個Runnable接口對象包裝成一個 Callable接口對象, 然后放到 workQueue里等待調度執行. 當然, 執行的啟動也是調用了thread的start來做到的, 只不過這里被包裝掉了. 另外, 這里的thread是會被重復利用的, 所以這里要退出主線程, 需要執行以下shutdown方法以示退出使用線程池. 扯遠了.

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

第六種:BlockingQueue

同時,在concurrent包中,還提供了BlockingQueue(隊列)來操作線程,BlockingQueue的主要的用法是在線程間安全有效的傳遞數據,因此,第六種方法也出來了:

//開始計時String start = getTheTimeInMilliseconds();System.out.println("start = " + start);//數組型隊列,長度為1BlockingQueue queue = new ArrayBlockingQueue(1);Thread t = new Thread(() -> {//子線程進行字符串連接操作int num = 1000;String s = "";for (int i = 0; i < num; i++) {s += "Java" + i;}System.out.println("t Over s =" + s);try {//在隊列中加入數據queue.put("OK");} catch (InterruptedException e) {e.printStackTrace();}});t.start();try {queue.take();//主線程在隊列中獲取數據,take()方法會阻塞隊列,ps還有不會阻塞的方法} catch (InterruptedException e) {e.printStackTrace();}String end = getTheTimeInMilliseconds();System.out.println("end = " + end);

第七種:CyclicBarrier

第七種方式,還是concurrent包,只不過這次試用CyclicBarrier類:

CyclicBarrier字面意思回環柵欄,通過它可以實現讓一組線程等待至某個狀態之后再全部同時執行。叫做回環是因為當所有等待線程都被釋放以后,CyclicBarrier可以被重用。

//開始計時String start = getTheTimeInMilliseconds();System.out.println("start = " + start);//參數為線程數CyclicBarrier barrier = new CyclicBarrier(2);Thread t = new Thread(() -> {//子線程進行字符串連接操作int num = 1000;String s = "";for (int i = 0; i < num; i++) {s += "Java" + i;}System.out.println("t Over s =" + s);try {//阻塞barrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}});t.start();try {barrier.await();//也阻塞,并且當阻塞數量達到指定數目時同時釋放} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}String end = getTheTimeInMilliseconds();System.out.println("end = " + end);

實際是上面這種方法是不太嚴謹的,因為在子線程阻塞之后如果還有代碼是會繼續執行的,當然本例中后面是沒有代碼可執行了,可以近似理解為是子線程的運行時間。

問題

扒拉出這么方法都可以實現主線程等待子線程的方法,上個問題:

幾萬,幾十萬的數據情況下,只能一條信息一條信息發送,需要優化消費時間

保證每條數據都被消費掉,并且統計所有失敗的記錄,失敗的原因

小弟綜合實際寫的代碼,上demo,求各路大佬指教代碼中的缺陷,因為這塊不熟,面向百度編程使用的事淋漓盡致,所以老感覺有坑,但是又不知道在哪,賊尷尬

/*** 業務代碼精簡版*/private static AtomicInteger atomicInteger = new AtomicInteger(0);private static final CountDownLatch latch = new CountDownLatch(100);private static ExecutorService pool = new ThreadPoolExecutor(2, 4,1000, TimeUnit.SECONDS,new LinkedBlockingDeque<Runnable>(1000),new ThreadPoolExecutor.DiscardOldestPolicy());public static void main(String[] args) {System.out.println("主線程開始執行…… ……");// 需要統計每個數據的消費結果List<Map<String, Integer>> resultMap = new ArrayList<>();for (int i = 0; i < 100; i++) {pool.execute(() -> {try {synchronized (TestThread.class){Map<String, Integer> map = new Hashtable<>();// 假裝獲取了每個數據消費結果map.put("success", 0);resultMap.add(map);atomicInteger.getAndIncrement();}} catch (Exception e) {e.printStackTrace();} finally {latch.countDown();}});}try {latch.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("成功數量" + atomicInteger.get());System.out.println(resultMap);}

總結

以上是生活随笔為你收集整理的【多线程】学习记录七种主线程等待子线程结束之后在执行的方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 私人毛片 | 蜜桃色一区二区三区 | 国产偷人 | 特黄特色大片免费视频大全 | 欧美激情在线观看视频 | 婷婷成人综合网 | 国产精品久久久久久久免费观看 | 亚洲精品国产成人av在线 | 国产伦精品一区二区三区照片91 | 国产一级性生活 | 91久精品| 91亚洲精品久久久久久久久久久久 | 欧美精品第一区 | 久草视频福利在线 | 国产在线精品成人欧美 | 日韩一级影片 | 欧美gv在线观看 | 五月综合激情日本mⅴ | 久久久久久久久国产精品一区 | a一级网站 | 农村末发育av片一区二区 | 第四色视频 | 99国产精品白浆在线观看免费 | 欧美性啪啪| 人妖一区二区三区 | 丁香花电影免费播放在线观看 | 自慰无码一区二区三区 | 奇米影视狠狠 | 激情av在线播放 | 精品乱码一区内射人妻无码 | 欧美一区二区三区久久 | 亚洲人视频在线观看 | 深田咏美在线x99av | 人妻 校园 激情 另类 | 欧美三级视频在线观看 | 97日韩精品 | 好看的av网址 | 日本午夜免费 | 人人精品视频 | 在线播放免费av | 97人妻精品一区二区三区视频 | 欧美国产日韩在线 | 碧蓝之海动漫在线观看免费高清 | 国产美女av在线 | 去毛片 | 青春草久久 | brazzers欧美极品少妇 | 久草成人 | 91视频精选 | 欧美伊人网 | 全国男人天堂网 | 天天看片中文字幕 | 久久久五月| 国产精品久久久免费 | 久久8| 天天天操| 久久久久一区二区三区四区 | 久久久久久久久久久97 | 国产丝袜精品视频 | 麻豆视频网站入口 | 综合婷婷 | 色吧视频| 狠狠操狠狠摸 | 国产午夜成人久久无码一区二区 | 中文无码日韩欧 | 日韩avwww| 800av在线视频 | 国产精品v亚洲精品v日韩精品 | 久久黄色一级 | 日本中文字幕在线免费观看 | 天天艹日日干 | 日韩激情视频网站 | 性日韩 | 黄色理论视频 | 中国一级片黄色一级片黄 | 精品视频免费在线 | 在线看三级 | 国产av一区二区三区最新精品 | 中国国产黄色片 | 午夜九九 | 国产素人在线观看 | 欧美日韩中文字幕 | 亚洲精品系列 | 4hu在线观看 | 麻豆免费视频 | 日韩精品色 | 亚洲码在线观看 | 人妻洗澡被强公日日澡电影 | 男女爽爽视频 | 亚洲第一色 | 国产99在线 | 亚洲 | 日韩三级国产精品 | 成年人黄色免费视频 | 黄色中文字幕 | 激情xxxx | 一本大道一区二区 | 17c精品麻豆一区二区免费 | 天天舔天天摸 | 大尺度一区二区 |