工作總往往會遇到異步去執行某段邏輯, 然后先處理其他事情, 處理完后再把那段邏輯的處理結果進行匯總的場景, 這時候就需要使用線程了.
一個線程啟動之后, 是異步的去執行需要執行的內容的, 不會影響主線程的流程, 往往需要讓主線程指定后, 等待子線程的完成. 這里有幾種方式.
站在主線程的角度, 我們可以分為主動式和被動式.
主動式指主線程主動去檢測某個標志位, 判斷子線程是否已經完成. 被動式指主線程被動的等待子線程的結束, 很明顯, 比較符合人們的胃口. 就是你事情做完了, 你告訴我, 我匯總一下, 哈哈.
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 ---------------------------------------------------------------------------
參考:記不得了,不好意思啊。