1. 程式人生 > >主執行緒等待子執行緒結束

主執行緒等待子執行緒結束

在很多時候,我們期望實現這麼一種功能:在主執行緒中啟動一些子執行緒,等待所有子執行緒執行結束後,主執行緒再繼續執行。比如:老闆分配任務,眾多工人開始工作,等所有工人完成工作後,老闆進行檢查。

解決方法分析:

  1. 主執行緒通過join等待所有子執行緒完成後,繼續執行;
  2. 主執行緒知道子執行緒的數量、未完成子執行緒數量,主執行緒等待所有子執行緒完成後,才繼續執行。

通過join實現

第一種方式,可以直接呼叫Java API中關於執行緒的join方法等待該執行緒終止,可以直接實現。

每個工人都是一個執行緒,其run方法是工作的實現,每個工人通過名字進行區分,具體程式碼如下:

package howe.demo.thread.join;


import java.util.Random;
import java.util.concurrent.TimeUnit;


/**
 * @author liuxinghao
 * @version 1.0 Created on 2014年9月12日
 */
public class Worker extends Thread {
    private String workerName;


    public Worker(String workerName) {
        this.workerName = workerName;
    }


    /**
     * @see java.lang.Thread#run()
     */
    @Override
    public void run() {
        System.out.println(this.workerName + "正在幹活...");
        try {
            TimeUnit.SECONDS.sleep(new Random().nextInt(10));
        } catch (InterruptedException e) {
        }
        System.out.println(this.workerName + "活幹完了!");
    }


    public String getWorkerName() {
        return workerName;
    }
}

老闆招收工人,然後安排工人工作,之後等待工人工作完,檢查工人的工作成果(資本家啊。。。),具體程式碼如下:

package howe.demo.thread.join;


import java.util.List;


/**
 * @author liuxinghao
 * @version 1.0 Created on 2014年9月12日
 */
public class Boss {
    private List<Worker> workers;


    public Boss(List<Worker> workers) {
        System.out.println("老闆招收工人。");
        this.workers = workers;
    }


    public void work() {
        System.out.println("老闆開始安排工人工作...");
        for (Worker worker : workers) {
            System.out.println("老闆安排" + worker.getWorkerName() + "的工作");
            worker.start();
        }
        System.out.println("老闆安排工作結束...");


        System.out.println("老闆正在等所有的工人幹完活......");
        for (Worker w : workers) {
            try {
                w.join();
            } catch (InterruptedException e) {
            }
        }
        System.out.println("工人活都幹完了,老闆開始檢查了!");
    }
}

現在寫main方法進行測試:

package howe.demo.thread.join;


import java.util.ArrayList;
import java.util.List;


/**
 * @author liuxinghao
 * @version 1.0 Created on 2014年9月12日
 */
public class JoinDemo {
    public static void main(String[] args) {
        Worker w1 = new Worker("張三");
        Worker w2 = new Worker("李四");
        Worker w3 = new Worker("王五");


        List<Worker> workers = new ArrayList<Worker>();
        workers.add(w1);
        workers.add(w2);
        workers.add(w3);


        Boss boss = new Boss(workers);
        boss.work();


        System.out.println("main方法結束");
    }
}

執行結果為:

老闆招收工人。
老闆開始安排工人工作...
老闆安排張三的工作
老闆安排李四的工作
張三正在幹活...
老闆安排王五的工作
李四正在幹活...
老闆安排工作結束...
老闆正在等所有的工人幹完活......
王五正在幹活...
王五活幹完了!
張三活幹完了!
李四活幹完了!
工人活都幹完了,老闆開始檢查了!
main方法結束

通過計數器實現

第二種方式可以自己實現一種計數器,用於統計子執行緒總數、未完成執行緒數,當未完成執行緒數大約0,主執行緒等待;當未完成執行緒數等於0,主執行緒繼續執行。

當然,既然我們現在想到這種方式,Java API的團隊當然也會想到,JDK 1.5提供了CountDownLatch用於實現上述方法。

於是對上述的工人方法進行修改:

package howe.demo.thread.cdl;


import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;


/**
 * @author liuxinghao
 * @version 1.0 Created on 2014-9-12
 */
public class Worker extends Thread {
    private CountDownLatch downLatch;
    private String workerName;


    public Worker(CountDownLatch downLatch, String workerName) {
        this.downLatch = downLatch;
        this.workerName = workerName;
    }


    public void run() {
        System.out.println(this.workerName + "正在幹活...");
        try {
            TimeUnit.SECONDS.sleep(new Random().nextInt(10));
        } catch (InterruptedException ie) {
        }
        System.out.println(this.workerName + "活幹完了!");
        this.downLatch.countDown();
    }


    public String getWorkerName() {
        return workerName;
    }
}

latch.countDown(),是用於在子執行緒執行結束後計數器減一,即未完成子執行緒數減一。

老闆類也得做出相應的修改:

package howe.demo.thread.cdl;


import java.util.List;
import java.util.concurrent.CountDownLatch;


/**
 * @author liuxinghao
 * @version 1.0 Created on 2014-9-12
 */
public class Boss {
    private List<Worker> workers;
    private CountDownLatch downLatch;


    public Boss(List<Worker> workers, CountDownLatch downLatch) {
        this.workers = workers;
        this.downLatch = downLatch;
    }


    public void work() {
        System.out.println("老闆開始安排工人工作...");
        for (Worker worker : workers) {
            System.out.println("老闆安排" + worker.getWorkerName() + "的工作");
            worker.start();
        }
        System.out.println("老闆安排工作結束...");


        System.out.println("老闆正在等所有的工人幹完活......");
        try {
            this.downLatch.await();
        } catch (InterruptedException e) {
        }
        System.out.println("工人活都幹完了,老闆開始檢查了!");
    }


}

latch.await(),是等待子執行緒結束。

編寫main方法進行驗證:

package howe.demo.thread.cdl;


import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;


/**
 * @author liuxinghao
 * @version 1.0 Created on 2014年9月15日
 */
public class CountDownLatchDemo {
    public static void main(String[] args) {
        CountDownLatch latch = new CountDownLatch(3);


        Worker w1 = new Worker(latch, "張三");
        Worker w2 = new Worker(latch, "李四");
        Worker w3 = new Worker(latch, "王五");


        List<Worker> workers = new ArrayList<Worker>();
        workers.add(w1);
        workers.add(w2);
        workers.add(w3);


        Boss boss = new Boss(workers, latch);


        boss.work();


        System.out.println("main方法結束");
    }
}

執行結果為:

老闆開始安排工人工作...
老闆安排張三的工作
老闆安排李四的工作
張三正在幹活...
老闆安排王五的工作
李四正在幹活...
老闆安排工作結束...
老闆正在等所有的工人幹完活......
王五正在幹活...
王五活幹完了!
李四活幹完了!
張三活幹完了!
工人活都幹完了,老闆開始檢查了!
main方法結束

使用迴圈柵欄CyclicBarrier實現

還有一種實現,這種方式不會阻塞主執行緒,但是會監聽所有子執行緒結束。此處在上述的工人老闆的場景中使用的話,程式碼如下:

工人類:

package howe.demo.thread.cyclicbarrier;


import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;


/**
 * @author liuxinghao
 * @version 1.0 Created on 2014年9月12日
 */
public class Worker extends Thread {
    private String workerName;
    private CyclicBarrier barrier;


    public Worker(String workerName, CyclicBarrier barrier) {
        this.workerName = workerName;
        this.barrier = barrier;
    }


    @Override
    public void run() {
        System.out.println(this.workerName + "正在幹活...");
        try {
            TimeUnit.SECONDS.sleep(new Random().nextInt(10));
        } catch (InterruptedException e) {
        }
        System.out.println(this.workerName + "活幹完了!");


        try {
            barrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }


    public String getWorkerName() {
        return workerName;
    }
}

老闆類:

package howe.demo.thread.cyclicbarrier;


import java.util.List;


/**
 * @author liuxinghao
 * @version 1.0 Created on 2014-9-12
 */
public class Boss {
    private List<Worker> workers;


    public Boss(List<Worker> workers) {
        this.workers = workers;
    }


    public void work() {
        System.out.println("老闆開始安排工人工作...");
        for (Worker worker : workers) {
            System.out.println("老闆安排" + worker.getWorkerName() + "的工作");
            worker.start();
        }
        System.out.println("老闆安排工作結束...");


        System.out.println("老闆正在等所有的工人幹完活......");
    }


}

main方法測試:

package howe.demo.thread.cyclicbarrier;


import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CyclicBarrier;


/**
 * @author liuxinghao
 * @version 1.0 Created on 2014年9月15日
 */
public class CyclicBarrierDemo {
    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(3, new Runnable() {
            @Override
            public void run() {
                System.out.println("工人活都幹完了,老闆開始檢查了!");
            }
        });


        Worker w1 = new Worker("張三", barrier);
        Worker w2 = new Worker("李四", barrier);
        Worker w3 = new Worker("王五", barrier);


        List<Worker> workers = new ArrayList<Worker>();
        workers.add(w1);
        workers.add(w2);
        workers.add(w3);


        Boss boss = new Boss(workers);
        boss.work();


        System.out.println("main方法結束");
    }
}

執行結果為:

老闆開始安排工人工作...
老闆安排張三的工作
老闆安排李四的工作
張三正在幹活...
老闆安排王五的工作
李四正在幹活...
老闆安排工作結束...
老闆正在等所有的工人幹完活......
王五正在幹活...
main方法結束
李四活幹完了!
王五活幹完了!
張三活幹完了!
工人活都幹完了,老闆開始檢查了!

通過結果分析可以很清楚的看出,boss物件的work方法執行結束後,main方法即開始執行。(此處“老闆正在等所有的工人幹完活......”列印之後是“王五正在幹活...”,然後才是“main方法結束”,是因為對於cpu的搶佔,甚至有一定的概率是“main方法結束”會在最後列印。)

假設有這麼一個功能,我們需要向資料庫批量寫入一些記錄,然後記錄這個操作使用的時間,但是我們又不想影響其他操作(即不想阻塞主執行緒),這個時候CyclicBarrier就派上用場了。

相關推薦

執行等待執行結束

在很多時候,我們期望實現這麼一種功能:在主執行緒中啟動一些子執行緒,等待所有子執行緒執行結束後,主執行緒再繼續執行。比如:老闆分配任務,眾多工人開始工作,等所有工人完成工作後,老闆進行檢查。 解決方法分析: 主執行緒通過join等待所有子執行緒完成後,繼續執行;主執行緒知道

java 執行等待執行結束

第一種方式join/** * Date:2016年9月7日下午7:43:13 * Copyright (c) 2016, www.bwbroad.com All Rights Reserved. * */ package test.join; import tes

Java多執行--讓執行等待執行執行完畢

參考連結:https://www.cnblogs.com/eoss/p/5902939.html 使用Java多執行緒程式設計時經常遇到主執行緒需要等待子執行緒執行完成以後才能繼續執行,那麼接下來介紹一種簡單的方式使主執行緒等待。 java.util.concurrent.CountDown

Java實現執行等待執行join,CountDownLatch

本文介紹兩種主執行緒等待子執行緒的實現方式,以5個子執行緒來說明: 1、使用Thread的join()方法,join()方法會阻塞主執行緒繼續向下執行。 2、使用Java.util.concurrent中的CountDownLatch,是一個倒數計數器。初始化時先設定

效能優化-多執行-執行等待執行完成場景

專案 出行專案 需求 今日訂單查詢優化 場景描述 根據時間查詢出今日訂單,根據訂單去mongo查詢出規矩點,根據軌跡點去呼叫高德的地理/逆地理編碼介面(https://lbs.amap.com/api/webservice/guide/api/georegeo

Java Thread.join()詳解--父執行等待執行結束後再結束

一、使用方式。 join是Thread類的一個方法,啟動執行緒後直接呼叫,例如: ? 1 Thread t = new AThread(); t.start(); t.join();

java 執行等待執行執行完後再執行

這裡記錄一下下面這種情況:主執行緒需要等待多個子執行緒執行完後再執行。 我們先看一下下面的場景: package com.java4all.mypoint; import java.util.concurrent.CountDownLatch; /*

Java執行池ExecutorService時讓執行等待執行完成後繼續處理

(() -> { try { System.out.println(finalI + " 我執行了。。。"); Thread.sleep(5000L);

Java 執行執行等待執行awaitTermination方法使用詳解

    Java中在使用Executors執行緒池時,有時場景需要主執行緒等各子執行緒都執行完畢後再執行。這時候就需要用到ExecutorService介面中的awaitTermination方法,我們來看看原始碼中對該方法的說明:大概意思是這樣的:該方法呼叫會被阻塞,並且在

java執行執行等待執行執行完成

Java如何等待子執行緒執行結束 今天討論一個入門級的話題, 不然沒東西更新對不起空間和域名~~ 工作總往往會遇到非同步去執行某段邏輯, 然後先處理其他事情, 處理完後再把那段邏輯的處理結果進行彙總的產景, 這時候就需要使用執行緒了. 一個執行緒啟動之後, 是非同

執行-join方法(執行等待執行執行完畢)

多執行緒中的join方法 join主要的作用就是讓主執行緒 等待 子執行緒 執行完畢之後,才讓主執行緒繼續執行。 話不多說,直接看程式碼例子就好。 父執行緒 package com.luoy.Thread.join; public class Fa

關於使用CyclicBarrier使執行等待執行執行完之後再向下執行的問題

"pool-1-thread-2" prio=6 tid=0x00000000067f7800 nid=0x1534 at breakpoint[0x000000000876f000]    java.lang.Thread.State: RUNNABLE at com.iteye.wwwcomy.thre

python中執行等待執行完成的實現(join())

有時候遇到多程程處理的場景,主執行緒要等待子執行緒完成資料解析,然後主執行緒才利用子執行緒的資料做下一步操作,那麼python的實現方式是在主執行緒中呼叫子執行緒的join方法,這樣主執行緒在子執

java 如何實現等待執行結束

工作中往往會遇到非同步去執行某段邏輯, 然後先處理其他事情, 處理完後再把那段邏輯的處理結果進行彙總的產景, 這時候就需要使用執行緒了。 一個執行緒啟動之後, 是非同步的去執行需要執行的內容的, 不會影響主執行緒的流程,  往往需要讓主執行緒指定後, 等待子執行緒的完成. 這裡有幾種方式. 站在 主執行緒的

python執行執行結束順序

引用自 主執行緒退出對子執行緒的影響--YuanLi 的一段話: 對於程式來說,如果主程序在子程序還未結束時就已經退出,那麼Linux核心會將子程序的父程序ID改為1(也就是init程序),當子程序結束後會由init程序來回收該子程序。 主執行緒退出後子執行緒的狀態依賴於它所在的程序,如果程序沒有退出的話子執

Android執行執行中傳送資訊

主要用到了Handler類,Looper類和Message類 先介紹下這幾個類 Looper類,是用來為一個執行緒開啟一個訊息佇列,預設情況下Android下新開啟的執行緒沒有開啟訊息佇列的,除了主執行緒外,主執行緒系統會預設為其開啟一個訊息佇列;looper是通過MessageQueu

ThreadPool執行池使用及解決執行執行執行順序問題

 執行緒池建立五個執行緒,每個執行緒往list中新增100個元素。synchronized只鎖執行緒共享變數list物件,程式碼段內僅新增元素及列印資訊。設定10ms睡眠時間給其餘執行緒機會。 ExecutorService fixedThreadPool = Execut

Unity進階篇:執行執行概念及注意點

先理解一下什麼是執行緒: 執行緒是作業系統級別的概念,現代作業系統都實現並且支援執行緒,執行緒的排程對應用開發者是透明的,開發者無法預期某執行緒在何時被排程執行。基於此,一般那種隨機出現的BUG,多與

【2019春招準備:22.執行生命週期(執行執行)】

參考:強烈推薦 https://blog.csdn.net/u013905744/article/details/73741056 run java application: 建立一個java虛擬機器程序,main執行緒和userThread都可以在裡面跑,當沒有執行緒的時候,退出程

執行執行資源衝突,解決方案

問題描述,  我開發的任性動圖軟體,曾經遇到過這樣的問題:      任性動圖有一個功能是塗鴉功能,就是將你的塗鴉過程生成動圖,怎麼實現的呢?      有一個主顯示記憶體,用以顯示介面影象