1. 程式人生 > >[Java][Android] 多執行緒同步-主執行緒等待所有子執行緒完成案例

[Java][Android] 多執行緒同步-主執行緒等待所有子執行緒完成案例

有時候我們會遇到這樣的問題:做一個大的事情可以被分解為做一系列相似的小的事情,而小的事情無非就是引數上有可能不相同而已!

此時,如果不使用執行緒,我們勢必會浪費非常多的時間來完成整個大的事情,而使用執行緒的話將會存在這樣的問題:

主執行緒啟動所有子執行緒併發執行後主執行緒就直接返回了,導致外部函式判讀整個大的事情完成了,但是實際上並沒有完成!

針對以上情況我想我會採用多執行緒方式執行同時解決主執行緒等待子執行緒的問題。如圖:


在這裡我使用Java進行案例分析。

首先建立一個執行緒管理類,用於啟動所有子執行緒和等待所有子執行緒完成,在這裡不使用休眠一段時間後迴圈檢測的方式(消耗CUP同時消耗時間,全部完成時間不夠及時等缺點);而是使用等待臨界值的方式。ThreadManager.java如下:

public class ThreadManager implements NotifyInterface {
	private final Object mLock = new Object();
	private int mCount = 0;
	private int endCount = 0;

	public ThreadManager(int count) {
		System.out.println("Manager In.");

		this.mCount = count;

		this.addThread();

		synchronized (mLock) {
			while (true) {
				if (checkEnd())
					break;
				try {
					mLock.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

		System.out.println("Manager Out.");
	}

	private void addThread() {
		System.out.println("Manager addThread().");

		for (int i = 1; i <= mCount; i++) {
			ThreadDoThing dThread = new ThreadDoThing(i, "T" + i, this);
			// Start
			dThread.start();
		}

	}

	private boolean checkEnd() {
		boolean bFlag = false;
		bFlag = endCount >= mCount;

		System.out.println("Manager checkEnd().Return is:" + bFlag);

		return bFlag;
	}

	@Override
	public void runEnd() {
		synchronized (mLock) {
			++endCount;

			mLock.notifyAll();
		}
	}
}

此類整合自:NotifyInterface介面,NotifyInterface是用於子執行緒通知主執行緒自己已經完成工作所用類,ThreadManager例項化時將傳入一個int值,用於設定啟動的子執行緒數,當然這裡是為了簡單介紹所以採用的這樣的方式,實際情況可能更加複雜。

在例項化後  進入構造方法,此時將會啟動子執行緒,啟動後進入迴圈等待中,當檢測到所有子執行緒完成時就退出迴圈,沒有就將進入臨界值等待,直到通過介面通知主執行緒完成時將會通知臨界值一次,此時迴圈將會執行一次,如果不滿足退出條件將繼續等待臨界值。直到滿足為止。

NotifyInterface介面如下:

public interface NotifyInterface {
	
	public abstract void runEnd();

}

測試用的子執行緒ThreadDoThing.java如下:
public class ThreadDoThing extends Thread {
	private NotifyInterface mInterface = null;
	private int mId = 0;
	private String mArgs = null;

	public ThreadDoThing(int id, String args, NotifyInterface iface) {
		this.mId = id;
		this.mArgs = args;
		this.AddInterface(iface);
	}

	public void AddInterface(NotifyInterface iface) {
		this.mInterface = iface;
	}

	@Override
	public void run() {
		System.out.println("ThreadDoThing Id is:" + this.mId + " Args is:" + this.mArgs);
		System.out.println(this.mId + ":Doing...");

		int sleepTime = (int) (Math.random() * 1000);

		try {
			Thread.sleep(sleepTime);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(this.mId + ":SleepTime is:" + sleepTime);

		this.notifyEnd();

		System.out.println(this.mId + ":Do End.");
	}

	private void notifyEnd() {
		if (this.mInterface != null)
			this.mInterface.runEnd();

		System.out.println(this.mId + ":Notify End.");
	}
}

此類繼承自Thread類,可直接重寫Run()方法完成所做工作!

在工作中,我使用了隨機一個1s內的休眠來代替所做工作的時間,完成後呼叫介面通知完成。

測試方法如下:

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ThreadManager manager = new ThreadManager(10);
	}

測試結果:
Manager In.
Manager addThread().
ThreadDoThing Id is:1 Args is:T1
ThreadDoThing Id is:2 Args is:T2
2:Doing...
1:Doing...
ThreadDoThing Id is:3 Args is:T3
ThreadDoThing Id is:4 Args is:T4
3:Doing...
4:Doing...
ThreadDoThing Id is:5 Args is:T5
5:Doing...
ThreadDoThing Id is:6 Args is:T6
Manager checkEnd().Return is:false
ThreadDoThing Id is:8 Args is:T8
ThreadDoThing Id is:7 Args is:T7
8:Doing...
ThreadDoThing Id is:9 Args is:T9
9:Doing...
6:Doing...
ThreadDoThing Id is:10 Args is:T10
7:Doing...
10:Doing...
3:SleepTime is:111
3:Notify End.
3:Do End.
Manager checkEnd().Return is:false
5:SleepTime is:142
5:Notify End.
Manager checkEnd().Return is:false
5:Do End.
4:SleepTime is:199
4:Notify End.
Manager checkEnd().Return is:false
4:Do End.
7:SleepTime is:342
7:Notify End.
Manager checkEnd().Return is:false
7:Do End.
10:SleepTime is:346
10:Notify End.
Manager checkEnd().Return is:false
10:Do End.
6:SleepTime is:397
6:Notify End.
Manager checkEnd().Return is:false
6:Do End.
9:SleepTime is:468
9:Notify End.
Manager checkEnd().Return is:false
9:Do End.
1:SleepTime is:475
1:Notify End.
Manager checkEnd().Return is:false
1:Do End.
2:SleepTime is:686
Manager checkEnd().Return is:false
2:Notify End.
2:Do End.
8:SleepTime is:828
8:Notify End.
Manager checkEnd().Return is:true
8:Do End.
Manager Out.

實際情況可能更加複雜,甚至子執行緒下還有更多的子執行緒!

具體情況大家可以衍生考慮,檢測是否全部返回也可以有多種方式甚至設定新增一個定時器之類的。

以後有時間畫一個詳細點的圖!

相關推薦

[Java][Android] 執行同步-執行等待所有執行完成案例

有時候我們會遇到這樣的問題:做一個大的事情可以被分解為做一系列相似的小的事情,而小的事情無非就是引數上有可能不相同而已! 此時,如果不使用執行緒,我們勢必會浪費非常多的時間來完成整個大的事情,而使用執行緒的話將會存在這樣的問題: 主執行緒啟動所有子執行緒併發執行後主執行緒就

java執行等待所有執行執行完畢在執行(常見面試題)

java主執行緒等待所有子執行緒執行完畢在執行,這個需求其實我們在工作中經常會用到,比如使用者下單一個產品,後臺會做一系列的處理,為了提高效率,每個處理都可以用一個執行緒來執行,所有處理完成了之後才

JAVA執行等待所有執行執行完成執行執行

         如標題,此功能主要是JDK1.5引入的java.util.concurrent包下的CountDownLatch類,此類據介紹為以執行緒輔助類,通過執行緒計數器來實現一個或多個主執行緒等待其下所有子執行緒執行完後主執行緒再繼續執行的功能。        

併發問題和執行等待所有執行執行完畢再執行

問題引出: 我們對資料庫的操作是一個耗時過程,假如我們需要讓資料庫批量操作完成之後,再跳轉到另外一個頁面,注意:是批量操作完成之後再跳轉。 分析:以上需求我們遇到2個難點, 第一個難點是怎麼控制併發問題, 第二個難點是怎麼使主執行緒等待所有子執行緒完成之後再執行。 首先

Java CompletableFuture:allOf等待所有非同步執行任務結束

private void method() throws ExecutionException, InterruptedException { CompletableFuture<String> f1 = CompletableFuture.supplyAsync(()

Android程序app中Application回撥onCreate()方法被執行次分析及解決

最近工作中碰到一個問題,在優化app,使用DDMS檢視Application log過程中看到,app啟動了三個程序,一個主程序,兩個附帶的程序。如下圖可看到一個app啟動的三個程序。  自定義Application回撥方法onCreate()被執行了3次。開始不知是何原因。 相

關於執行同步的問題(區域性變數實現執行同步

package com.bootdo.wang; /** * 5.使用區域性變數實現執行緒同步 * 如果使用ThreadLocal管理變數,則每一個使用該變數的執行緒都獲得該變數的副本, * 副本之間相互獨立,這樣每一個執行緒都可以隨意修改自己的變數副本,而不會對其他執行緒產生

關於執行同步的問題(原子變數實現執行同步

package com.bootdo.wang; import java.util.concurrent.atomic.AtomicInteger; /** * 7.使用原子變數實現執行緒同步 * 在java的util.concurrent.atomic包中提供了建立了原子型別變數的工

執行學習之--真的不能在執行裡更新UI嗎?

在我們學習多執行緒的路上,都會聽到這樣一句話: 不能在子執行緒裡更新UI,UI更新必須在UI執行緒中 why?為什麼不能在子執行緒中更新UI?如果在子執行緒中更新UI會怎樣? 為了模擬在子執行緒中更新UI的場景,簡單地寫了幾行程式碼:

執行同步3 ------ 訊號量實現程序或者執行之間的同步

基本概念       首先要注意,訊號量和訊號是完全兩碼事。訊號量是一個計數器,常用於處理程序或執行緒的同步問題,特別是對臨界資源訪問的同步。臨界資源可以簡單地理解為在某一時刻只能由一個程序或執行緒進行操作的資源。通常,程式對共享資源的訪問的程式碼只是很短的一段,但就是這一

java主線程等待所有線程執行完畢在執行(常見面試題)

我們 工具 -1 cap 比賽 div 20px caption 常見 java主線程等待所有子線程執行完畢在執行(常見面試題)java主線程等待所有子線程執行完畢在執行,這個需求其實我們在工作中經常會用到,比如用戶下單一個產品,後臺會做一系列的處理,為了提高效率,每個處理

Java線程同步基礎

當前 @override nts oid [] 源代碼 and 函數 先後 java學習的道路上呢總有一些麻煩的東西需要花費一些時間去理解,比如個人認為不好搞的多線程. 線程是並列運行的 因為是並列運行,所以有時候會發生資源搶占,從而導致參數變化; 比如醬紫

c#等待所有線程執行完畢方法

參數 運行 線程池 lte rtt nts monitor 事情 img 當我們在使用線程中,你會發現主線結束後子線程的結果才顯示出來。現在我要等待所以子線程結束,然後在顯示結果,怎麽做呢? 方法如下: 1、使用 ManualResetEvent,代碼如下: usi

java使用遞迴,複製資料夾下的所有檔案

1.先判斷要複製的檔案是資料夾還是檔案,如果是檔案,就進行復制,如果是資料夾,就進行下一層的迴圈,運用遞迴的特性,將所有的檔案進行復制。 2.存在問題,相對來說,使用字元流來進行復制有缺陷,在複製的過程中,對於複製的圖片啊,ppt什麼的檔案會有損害,可能不能開

獲取部門下的所有部門

第一次寫,呃呃,直接上程式碼把(本人還是菜鳥,如有不足,求大佬指點) /** 獲取部門下所有員工 * *@param depList 部門id集合 *@return 所有部門id */ private List<Integer>

java 執行同步

            執行緒屬性: 1.執行緒優先順序,   優先順序高度依賴於系統,不要讓程式的正確性依賴於優先順序。預設情況子執行緒會繼承父執行緒的優先順序。 2.守護執行緒,   唯一用途是為其他執行緒提供服務,當只剩

Java執行 - 執行同步 synchronized

synchronized是Java同步的基礎,只有徹底瞭解synchronized的物件鎖、可重入鎖...特性,將來在使用高階的ReentrantLock、ReentrantReadWriteLock才能得心應手 本文將透過大量的具體例項來了解synchronized的特性 具體例項

JavaJava“定時器和執行”實際應用——執行同步

一、任務目標     將任務<Java“定時器和多執行緒”實際應用——定時器配合多執行緒>中的兩個執行緒修改為互斥的,以保證兩個執行緒不會同時對此類屬性x進行修改。   二、執行緒同步機制     在Java中提供了同步機制,可以有效地防止資源衝突。同步機制使用 sy

Java基礎執行執行安全-同步鎖三種形式

首先,我們通過一個案例,演示執行緒的安全問題: 電影院要賣票,我們模擬電影院的賣票過程。假設要播放的電影是 “葫蘆娃大戰奧特曼”,本次電影的座位共100個(本場電影只能賣100張票)。我們來模擬電影院的售票視窗,實現多個視窗同時賣 “終結者”這場電影票(多個視窗一起賣這100張票)需要視窗