java高併發系列 - 第31天:獲取執行緒執行結果,這6種方法你都知道?
這是java高併發系列第31篇。
環境:jdk1.8。
java高併發系列已經學了不少東西了,本篇文章,我們用前面學的知識來實現一個需求:
在一個執行緒中需要獲取其他執行緒的執行結果,能想到幾種方式?各有什麼優缺點?
結合這個需求,我們使用6種方式,來對之前學過的知識點做一個回顧,加深記憶。
方式1:Thread的join()方法實現
程式碼:
package com.itsoku.chat31; import java.sql.Time; import java.util.concurrent.*; /** * 跟著阿里p7學併發,微信公眾號:javacode2018 */ public class Demo1 { //用於封裝結果 static class Result<T> { T result; public T getResult() { return result; } public void setResult(T result) { this.result = result; } } public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println(System.currentTimeMillis()); //用於存放子執行緒執行的結果 Result<Integer> result = new Result<>(); //建立一個子執行緒 Thread thread = new Thread(() -> { try { TimeUnit.SECONDS.sleep(3); result.setResult(10); } catch (InterruptedException e) { e.printStackTrace(); } }); thread.start(); //讓主執行緒等待thread執行緒執行完畢之後再繼續,join方法會讓當前執行緒阻塞 thread.join(); //獲取thread執行緒的執行結果 Integer rs = result.getResult(); System.out.println(System.currentTimeMillis()); System.out.println(System.currentTimeMillis() + ":" + rs); } }
輸出:
1566733162636
1566733165692
1566733165692:10
程式碼中通過join方式阻塞了當前主執行緒,當thread執行緒執行完畢之後,join方法才會繼續執行。
join的方式,只能阻塞一個執行緒,如果其他執行緒中也需要獲取thread執行緒的執行結果,join方法無能為力了。
關於join()方法和執行緒更詳細的使用,可以參考:執行緒的基本操作
方式2:CountDownLatch實現
程式碼:
package com.itsoku.chat31; import java.util.concurrent.*; /** * 跟著阿里p7學併發,微信公眾號:javacode2018 */ public class Demo2 { //用於封裝結果 static class Result<T> { T result; public T getResult() { return result; } public void setResult(T result) { this.result = result; } } public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println(System.currentTimeMillis()); CountDownLatch countDownLatch = new CountDownLatch(1); //用於存放子執行緒執行的結果 Demo1.Result<Integer> result = new Demo1.Result<>(); //建立一個子執行緒 Thread thread = new Thread(() -> { try { TimeUnit.SECONDS.sleep(3); result.setResult(10); } catch (InterruptedException e) { e.printStackTrace(); }finally { countDownLatch.countDown(); } }); thread.start(); //countDownLatch.await()會讓當前執行緒阻塞,當countDownLatch中的計數器變為0的時候,await方法會返回 countDownLatch.await(); //獲取thread執行緒的執行結果 Integer rs = result.getResult(); System.out.println(System.currentTimeMillis()); System.out.println(System.currentTimeMillis() + ":" + rs); } }
輸出:
1566733720406
1566733723453
1566733723453:10
上面程式碼也達到了預期效果,使用CountDownLatch
可以讓一個或者多個執行緒等待一批執行緒完成之後,自己再繼續;CountDownLatch
更詳細的介紹見:JUC中等待多執行緒完成的工具類CountDownLatch,必備技能
方式3:ExecutorService.submit方法實現
程式碼:
package com.itsoku.chat31; import java.util.concurrent.*; /** * 跟著阿里p7學併發,微信公眾號:javacode2018 */ public class Demo3 { public static void main(String[] args) throws ExecutionException, InterruptedException { //建立一個執行緒池 ExecutorService executorService = Executors.newCachedThreadPool(); System.out.println(System.currentTimeMillis()); Future<Integer> future = executorService.submit(() -> { try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } return 10; }); //關閉執行緒池 executorService.shutdown(); System.out.println(System.currentTimeMillis()); Integer result = future.get(); System.out.println(System.currentTimeMillis() + ":" + result); } }
輸出:
1566734119938
1566734119989
1566734122989:10
使用ExecutorService.submit
方法實現的,此方法返回一個Future
,future.get()
會讓當前執行緒阻塞,直到Future關聯的任務執行完畢。
相關知識:
- JAVA執行緒池,這一篇就夠了
- JUC中的Executor框架詳解1
- JUC中的Executor框架詳解2
方式4:FutureTask方式1
程式碼:
package com.itsoku.chat31;
import java.util.concurrent.*;
/**
* 跟著阿里p7學併發,微信公眾號:javacode2018
*/
public class Demo4 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(System.currentTimeMillis());
//建立一個FutureTask
FutureTask<Integer> futureTask = new FutureTask<>(() -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 10;
});
//將futureTask傳遞一個執行緒執行
new Thread(futureTask).start();
System.out.println(System.currentTimeMillis());
//futureTask.get()會阻塞當前執行緒,直到futureTask執行完畢
Integer result = futureTask.get();
System.out.println(System.currentTimeMillis() + ":" + result);
}
}
輸出:
1566736350314
1566736350358
1566736353360:10
程式碼中使用FutureTask
實現的,FutureTask實現了Runnable
介面,並且內部帶返回值,所以可以傳遞給Thread直接執行,futureTask.get()
會阻塞當前執行緒,直到FutureTask
構造方法傳遞的任務執行完畢,get方法才會返回。關於FutureTask
詳細使用,請參考:JUC中的Executor框架詳解1
方式5:FutureTask方式2
程式碼:
package com.itsoku.chat31;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
/**
* 跟著阿里p7學併發,微信公眾號:javacode2018
*/
public class Demo5 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(System.currentTimeMillis());
//建立一個FutureTask
FutureTask<Integer> futureTask = new FutureTask<>(() -> 10);
//將futureTask傳遞一個執行緒執行
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
futureTask.run();
}).start();
System.out.println(System.currentTimeMillis());
//futureTask.get()會阻塞當前執行緒,直到futureTask執行完畢
Integer result = futureTask.get();
System.out.println(System.currentTimeMillis() + ":" + result);
}
}
輸出:
1566736319925
1566736319970
1566736322972:10
建立了一個FutureTask
物件,呼叫futureTask.get()
會阻塞當前執行緒,子執行緒中休眠了3秒,然後呼叫futureTask.run();
當futureTask的run()方法執行完畢之後,futureTask.get()
會從阻塞中返回。
注意:這種方式和方式4的不同點。
關於FutureTask
詳細使用,請參考:JUC中的Executor框架詳解1
方式6:CompletableFuture方式實現
程式碼:
package com.itsoku.chat31;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
/**
* 跟著阿里p7學併發,微信公眾號:javacode2018
*/
public class Demo6 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(System.currentTimeMillis());
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 10;
});
System.out.println(System.currentTimeMillis());
//futureTask.get()會阻塞當前執行緒,直到futureTask執行完畢
Integer result = completableFuture.get();
System.out.println(System.currentTimeMillis() + ":" + result);
}
}
輸出:
1566736205348
1566736205428
1566736208429:10
CompletableFuture.supplyAsync
可以用來非同步執行一個帶返回值的任務,呼叫completableFuture.get()
會阻塞當前執行緒,直到任務執行完畢,get方法才會返回。
關於CompletableFuture
更詳細的使用見:JUC中工具類CompletableFuture,必備技能
java高併發系列目錄
- 第1天:必須知道的幾個概念
- 第2天:併發級別
- 第3天:有關並行的兩個重要定律
- 第4天:JMM相關的一些概念
- 第5天:深入理解程序和執行緒
- 第6天:執行緒的基本操作
- 第7天:volatile與Java記憶體模型
- 第8天:執行緒組
- 第9天:使用者執行緒和守護執行緒
- 第10天:執行緒安全和synchronized關鍵字
- 第11天:執行緒中斷的幾種方式
- 第12天JUC:ReentrantLock重入鎖
- 第13天:JUC中的Condition物件
- 第14天:JUC中的LockSupport工具類,必備技能
- 第15天:JUC中的Semaphore(訊號量)
- 第16天:JUC中等待多執行緒完成的工具類CountDownLatch,必備技能
- 第17天:JUC中的迴圈柵欄CyclicBarrier的6種使用場景
- 第18天:JAVA執行緒池,這一篇就夠了
- 第19天:JUC中的Executor框架詳解1
- 第20天:JUC中的Executor框架詳解2
- 第21天:java中的CAS,你需要知道的東西
- 第22天:JUC底層工具類Unsafe,高手必須要了解
- 第23天:JUC中原子類,一篇就夠了
- 第24天:ThreadLocal、InheritableThreadLocal(通俗易懂)
- 第25天:掌握JUC中的阻塞佇列
- 第26篇:學會使用JUC中常見的集合,常看看!
- 第27天:實戰篇,介面效能提升幾倍原來這麼簡單
- 第28天:實戰篇,微服務日誌的傷痛,一併幫你解決掉
- 第29天:高併發中常見的限流方式
- 第30天:JUC中工具類CompletableFuture,必備技能
阿里p7一起學併發,公眾號:路人甲java,每天獲取最新文章!
相關推薦
java高併發系列 - 第31天:獲取執行緒執行結果,這6種方法你都知道?
這是java高併發系列第31篇。 環境:jdk1.8。 java高併發系列已經學了不少東西了,本篇文章,我們用前面學的知識來實現一個需求: 在一個執行緒中需要獲取其他執行緒的執行結果,能想到幾種方式?各有什麼優缺點? 結合這個需求,我們使用6種方式,來對之前學過的知識點做一個回顧,加深記憶。 方式1:Thre
java高併發系列 - 第14天:JUC中的LockSupport工具類,必備技能
這是java高併發系列第14篇文章。 本文主要內容: 講解3種讓執行緒等待和喚醒的方法,每種方法配合具體的示例 介紹LockSupport主要用法 對比3種方式,瞭解他們之間的區別 LockSupport位於java.util.concurrent(簡稱juc)包中,算是juc中一個基礎類,juc中很多地
java高併發系列 - 第15天:JUC中的Semaphore,最簡單的限流工具類,必備技能
這是java高併發系列第15篇文章 Semaphore(訊號量)為多執行緒協作提供了更為強大的控制方法,前面的文章中我們學了synchronized和重入鎖ReentrantLock,這2種鎖一次都只能允許一個執行緒訪問一個資源,而訊號量可以控制有多少個執行緒可以同時訪問特定的資源。 Semaphore常用
java高併發系列 - 第16天:JUC中等待多執行緒完成的工具類CountDownLatch,必備技能
這是java高併發系列第16篇文章。 本篇內容 介紹CountDownLatch及使用場景 提供幾個示例介紹CountDownLatch的使用 手寫一個並行處理任務的工具類 假如有這樣一個需求,當我們需要解析一個Excel裡多個sheet的資料時,可以考慮使用多執行緒,每個執行緒解析一個sheet裡的資料
java高併發系列 - 第17天:JUC中的迴圈柵欄CyclicBarrier常見的6種使用場景及程式碼示例
這是java高併發系列第17篇。 本文主要內容: 介紹CyclicBarrier 6個示例介紹CyclicBarrier的使用 對比CyclicBarrier和CountDownLatch CyclicBarrier簡介 CyclicBarrier通常稱為迴圈屏障。它和CountDownLatch很相似,
java高併發系列 - 第21天:java中的CAS操作,java併發的基石
這是java高併發系列第21篇文章。 本文主要內容 從網站計數器實現中一步步引出CAS操作 介紹java中的CAS及CAS可能存在的問題 悲觀鎖和樂觀鎖的一些介紹及資料庫樂觀鎖的一個常見示例 使用java中的原子操作實現網站計數器功能 我們需要解決的問題 需求:我們開發了一個網站,需要對訪問量進行統計,使
java高併發系列 - 第22天:java中底層工具類Unsafe,高手必須要了解
這是java高併發系列第22篇文章,文章基於jdk1.8環境。 本文主要內容 基本介紹 通過反射獲取Unsafe例項 Unsafe中的CAS操作 Unsafe中原子操作相關方法介紹 Unsafe中執行緒排程相關方法 park和unpark示例 Unsafe鎖示例 Unsafe中保證變數的可見性 Unsafe
java高併發系列 - 第23天:JUC中原子類,一篇就夠了
這是java高併發系列第23篇文章,環境:jdk1.8。 本文主要內容 JUC中的原子類介紹 介紹基本型別原子類 介紹陣列型別原子類 介紹引用型別原子類 介紹物件屬性修改相關原子類 預備知識 JUC中的原子類都是都是依靠volatile、CAS、Unsafe類配合來實現的,需要了解的請移步: volati
java高併發系列 - 第24天:ThreadLocal、InheritableThreadLocal(通俗易懂)
java高併發系列第24篇文章。 環境:jdk1.8。 本文內容 需要解決的問題 介紹ThreadLocal 介紹InheritableThreadLocal 需要解決的問題 我們還是以解決問題的方式來引出ThreadLocal、InheritableThreadLocal,這樣印象會深刻一些。 目前
java高併發系列 - 第25天:掌握JUC中的阻塞佇列
這是java高併發系列第25篇文章。 環境:jdk1.8。 本文內容 掌握Queue、BlockingQueue介面中常用的方法 介紹6中阻塞佇列,及相關場景示例 重點掌握4種常用的阻塞佇列 Queue介面 佇列是一種先進先出(FIFO)的資料結構,java中用Queue介面來表示佇列。 Queue介面中
java高併發系列 - 第27天:實戰篇,介面效能成倍提升,讓同事刮目相看,現學現用
這是java高併發系列第27篇文章。 開發環境:jdk1.8。 案例講解 電商app都有用過吧,商品詳情頁,需要給他們提供一個介面獲取商品相關資訊: 商品基本資訊(名稱、價格、庫存、會員價格等) 商品圖片列表 商品描述資訊(描述資訊一般是由富文字編輯的大文字資訊) 資料庫中我們用了3張表儲存上面的資訊:
java高併發系列 - 第32天:高併發中計數器的實現方式有哪些?
這是java高併發系列第32篇文章。 java環境:jdk1.8。 本文主要內容 4種方式實現計數器功能,對比其效能 介紹LongAdder 介紹LongAccumulator 需求:一個jvm中實現一個計數器功能,需保證多執行緒情況下資料正確性。 我們來模擬50個執行緒,每個執行緒對計數器遞增100萬次
java高併發系列-第1天:必須知道的幾個概念
java高併發系列-第1天:必須知道的幾個概念 同步(Synchronous)和非同步(Asynchronous) 同步和非同步通常來形容一次方法呼叫,同步方法呼叫一旦開始,呼叫者必須等到方法呼叫返回後,才能繼續後續的行為。非同步方法呼叫更像一個訊息傳遞,一旦開始,方法呼叫就會立即返回,呼叫者就可以繼續後續的
java高併發系列 - 第12天JUC:ReentrantLock重入鎖
java高併發系列 - 第12天JUC:ReentrantLock重入鎖 本篇文章開始將juc中常用的一些類,估計會有十來篇。 synchronized的侷限性 synchronized是java內建的關鍵字,它提供了一種獨佔的加鎖方式。synchronized的獲取和釋放鎖由jvm實現,使用者不需要顯示的釋
java併發系列 - 第29天:高併發中常見的限流方式
這是java高併發系列第29篇。 環境:jdk1.8。 本文內容 介紹常見的限流演算法 通過控制最大併發數來進行限流 通過漏桶演算法來進行限流 通過令牌桶演算法來進行限流 限流工具類RateLimiter 常見的限流的場景 秒殺活動,數量有限,訪問量巨大,為了防止系統宕機,需要做限流處理 國慶期間,一般
java高併發系列 - 第6天:執行緒的基本操作
新建執行緒 新建執行緒很簡單。只需要使用new關鍵字建立一個執行緒物件,然後呼叫它的start()啟動執行緒即可。 Thread thread1 = new Thread1(); t1.start(); 那麼執行緒start()之後,會幹什麼呢?執行緒有個run()方法,start()會建立一個新的執行緒並讓
Java高併發程式設計(十):Java併發工具類
1. 等待多執行緒完成的CountDownLatch CountDownLatch允許一個或多個執行緒等待其他執行緒完成操作。 1.1 應用場景 假如有這樣一個需求:我們需要解析一個Excel裡多個sheet的資料,此時可以考慮使用多 執行緒,每個執行緒解析一個sheet裡的資料
Java高併發程式設計(八):Java併發容器和框架
1. ConcurrentHashMap 1.1 ConcurrentHashMap的優勢 在併發程式設計中使用HashMap可能導致程式死迴圈。而使用執行緒安全的HashTable效率又非 常低下,基於以上兩個原因,便有了ConcurrentHashMap的登場機會。
Mysql系列 - 第3天:管理員必備技能(必須掌握)
這是mysql系列第3篇文章。 環境:mysql5.7.25,cmd命令中進行演示。 在玩mysql的過程中,經常遇到有很多朋友在雲上面玩mysql的時候,說我建立了一個使用者為什麼不能登入?為什麼沒有許可權?等等各種問題,本文看完之後,這些都不是問題了。 本文主要內容 介紹Mysql許可權工作原理 檢視所
Mysql高手系列 - 第4天:DDL常見操作彙總
這是Mysql系列第4篇。 環境:mysql5.7.25,cmd命令中進行演示。 DDL:Data Define Language資料定義語言,主要用來對資料庫、表進行一些管理操作。 如:建庫、刪庫、建表、修改表、刪除表、對列的增刪改等等。 文中涉及到的語法用[]包含的內容屬於可選項,下面做詳細說明。 庫的管