問題:如何實現java主線程等待子線程執行完畢之后再執行?


  工作總往往會遇到異步去執行某段邏輯, 然后先處理其他事情, 處理完后再把那段邏輯的處理結果進行匯總的場景, 這時候就需要使用線程了.

  一個線程啟動之后, 是異步的去執行需要執行的內容的, 不會影響主線程的流程,  往往需要讓主線程指定后, 等待子線程的完成. 這里有幾種方式.

  站在主線程的角度, 我們可以分為主動式被動式.

  主動式指主線程主動去檢測某個標志位, 判斷子線程是否已經完成. 被動式指主線程被動的等待子線程的結束, 很明顯, 比較符合人們的胃口. 就是你事情做完了, 你告訴我, 我匯總一下, 哈哈.

1.      JoinDemo(主動式)

目的:等待當前線程的die

示例:

package com.test;

 

public class JoinDemo {

    public static void main(String[] args) throws Exception {

        //創建子線程,並啟動子線程

        Thread subThread = new Thread(new SubThread());

        subThread.start();

        //主線程處理其他工作,讓子線程異步去執行

        mainWork();

        //主線程其他工作完畢,等待子線程的結束, 調用join系列的方法即可(可以設置超時時間)

        subThread.join();

        System.out.println("Now all thread done!");

    }

    private static void mainWork() throws Exception{

        System.out.println("Main thread start work!");

        //sleep

        Thread.sleep(2000L);

        System.out.println("Main Thread work done!");

    }

    /**

     * 子線程類

     * @author fuhg

     */

    private static class SubThread implements Runnable{

        public void run() {

            // TODO Auto-generated method stub

            System.out.println("Sub thread is starting!");

            try {

                Thread.sleep(5000L);

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            System.out.println("Sub thread is stopping!");

        }

    }

}

 

2.      FutureDemo

  使用並發包下面的Future模式.

  Future是一個任務執行的結果, 他是一個將來時, 即一個任務執行, 立即異步返回一個Future對象, 等到任務結束的時候, 會把值返回給這個future對象里面. 我們可以使用    ExecutorService接口來提交一個線程.(注意:Future.get()為一個阻塞方法)

  示例:

  

package com.test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class FutureDemo {
	//創建一個容量為1的線程池
	static ExecutorService executorService = Executors.newFixedThreadPool(1);
	
	public static void main(String[] args) throws Exception {
		//創建線程並提交線程,同時獲取一個future對象
		Thread subThread = new Thread(new SubThread());
		Future future = executorService.submit(subThread);
		//主線程處理其他工作,讓子線程異步去執行
		mainWork();
		//阻塞,等待子線程結束
		future.get(); 
		System.out.println("Now all thread done!");
		//關閉線程池
		executorService.shutdown();
	}
	//主線程工作
	private static void mainWork(){
		System.out.println("Main thread start work!");
		try {
			Thread.sleep(2000L);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("Main Thread work done!");
	}
	/**
	 * 子線程類
	 * @author fuhg
	 */
	private static class SubThread implements Runnable{
		public void run() {
			// TODO Auto-generated method stub
			System.out.println("Sub thread is starting!");
			try {
				Thread.sleep(5000L);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("Sub thread is stopping!");
		}
	}
}

 

3.      CountDownDemo

  上面兩種情況在線程數為一兩個的時候,還可以,如果需要控制的線程數很多的話,再采取這種方式就有點過意不去了。

  第一種方法, 你要調用很多個線程的join, 特別是當你的線程不是for循環創建的, 而是一個一個創建的時候.

  第二種方法, 要調用很多的future的get方法, 同第一種方法.

 

  所以去Concurrent庫里面找找看還有什么東東吧。

  CountDownLanch 是一個倒數計數器, 給一個初始值(>=0), 然后每一次調用countDown就會減1, 這很符合等待多個子線程結束的場景: 一個線程結束的時候, countDown一次, 直到所有的線程都countDown了 , 那么所有子線程就都結束了.

  先看看CountDownLanch提供的方法吧

  

  

  await: 會阻塞等待計數器減少到0位置. 帶參數的await是多了等待時間.

  countDown: 將當前的計數減1

  getCount(): 返回當前的計數

  顯而易見, 我們只需要在子線程執行之前, 賦予初始化countDownLanch, 並賦予線程數量為初始值.

  每個線程執行完畢的時候, 就countDown一下.主線程只需要調用await方法, 可以等待所有子線程執行結束。

  示例:

  

package com.test;

import java.util.concurrent.CountDownLatch;

public class CountDownDemo {

	public static void main(String[] args) throws Exception {
		//定義線程數
		int subThreadNum = 5;
		//取得一個倒計時器,從5開始
		CountDownLatch countDownLatch = new CountDownLatch(subThreadNum);
		//依次創建5個線程,並啟動
		for (int i = 0; i < subThreadNum; i++) {
			new SubThread(2000*(i+1), countDownLatch).start();
		}
		//主線程工作
		mainWork();
		//等待所有的子線程結束
		countDownLatch.await();
		System.out.println("Main Thread work done!");
	}
	private static void mainWork(){
		System.out.println("Main thread start work!");
		try {
			Thread.sleep(2000L);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("Main Thread work done!");
	}
	/**
	 * 子線程類
	 * @author fuhg
	 */
	private static class SubThread extends Thread{
		
		private CountDownLatch countDownLatch;
		private long workTime;
		
		public SubThread(long workTime,CountDownLatch countDownLatch){
			this.workTime = workTime;
			this.countDownLatch = countDownLatch;
		}
		
		public void run() {
			// TODO Auto-generated method stub
			try {
				System.out.println("Sub thread is starting!");
				Thread.sleep(workTime);
				System.out.println("Sub thread is stopping!");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				//線程結束時,將計時器減一
				countDownLatch.countDown();
			}
		}
	}
}

 

 

 

-----------------------------------------------------end of file ---------------------------------------------------------------------------

  參考:記不得了,不好意思啊。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM