摘要:本人郵箱歡迎轉載轉載請注明網址代碼已經全部托管有需要的同學自行下載引言前面我們講了那么多有關線程的知識不知道讀者有沒有想過這么一個問題如果有這么一個比較耗時的任務必須使用線程來執行但是在這個任務執行完之后我需要得到這個線程的返回值以目前我們
引言本人郵箱:
歡迎轉載,轉載請注明網址 http://blog.csdn.net/tianshi_kco
github: https://github.com/kco1989/kco
代碼已經全部托管github有需要的同學自行下載
前面我們講了那么多有關線程的知識.不知道讀者有沒有想過這么一個問題,如果有這么一個比較耗時的任務,必須使用線程來執行,但是在這個任務執行完之后,我需要得到這個線程的返回值.以目前我們學到的知識,具體實現,我這里不說,大家自行發揮.除此之外,如果線程發生了非運行時異常,我們在主線程就會收到一堆錯誤信息.還有我們也無法判斷任務是否執行完成,有些人會說用Thread1.isAlive()就可以判斷任務是否執行完成.這是錯的,因為isAlive只是判斷線程是否存活,而無法判斷任務是否完成,兩者是不一樣的概念.如果有沒有不明白的,請考慮使用線程池ThreadPoolExecutor的情況.
以上說了那么多,其實就是為了引入今天要講的Callable,Future,FutureTask.ok,讓我們看一下這些類是干什么的.
*Callable 可以說是 Runnable的升級版本,既有拋出錯誤也有返回類型.
*Future 是執行異步任務后的返回值,這個接口包括一下幾個方法
* `cancel(boolean mayInterruptIfRunning)` 取消任務,如果`mayInterruptIfRunning`為`true`,即使該任務在運行也可以被中斷.否則在運行中的任務不能被取消. * `isCancelled`判斷任務是否被取消 * `isDone` 判斷任務是否完成 * `get` 獲取任務的返回值,如果任務有異常,則在調用這個方法的時候被拋出 * `get(long timeout, TimeUnit unit)` 在指定時間內等待獲取任務的返回值,如果任務有異常,則在調用這個方法的時候被拋出
FutureTask 是Runnable和Future的子類
例子1 獲取異步任務的返回值 Runnable 版本public class Demo1 { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println("main start"); FutureTask task = new FutureTask(() -> System.out.println("執行子任務"), "hello"); new Thread(task).start(); while (task.isDone()); System.out.println("任務返回結果:" + task.get()); System.out.println("main end"); } }
運行結果
main start
執行子任務
任務返回結果:hello
main end
public FutureTask(Runnable runnable, V result) 這個比較適合固定任務返回固定值的情況,如果返回的值需要進過計算,所以有多個情況,則不適合使用這個構造.
例子1 獲取異步任務的返回值 Callable 版本public class Demo2 { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println("main start"); FutureTask task = new FutureTask(() -> { int sum = 0; for (int i = 1; i <= 100; i++){ sum += i; } return sum; }); new Thread(task).start(); while (task.isDone()); System.out.println("任務返回結果:" + task.get()); System.out.println("main end"); } }
返回結果
例子3 測試運行時異常情況main start
任務返回結果:5050
main end
public class Demo3 { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println("main start"); FutureTask task = new FutureTask(() -> { System.out.println("正在執行子任務"); int i = 1 / 0; return 0; }); new Thread(task).start(); while (task.isDone()); System.out.println("任務返回結果:" + task.get()); System.out.println("main end"); } }
運行結果:
main start
正在執行子任務
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at com.kco.test18.demo.Demo3.main(Demo3.java:19)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.lang.ArithmeticException: / by zero
at com.kco.test18.demo.Demo3.lambda$main$0(Demo3.java:14)
at com.kco.test18.demo.Demo3$$Lambda$1/27095111.call(Unknown Source)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:745)
需要注意的是,這是拋出的異常是在調用task.get()才拋出的,如果把task.get()注釋掉,是不會拋出異常的.所以我們就可以對異常做一下自定義處理.比如寫到日志中.
例子4 取消正在執行的任務public class Demo4 { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println("main start"); FutureTask task = new FutureTask(() -> { System.out.println("start 正在執行子任務"); Thread.sleep(500); System.out.println("end 執行子任務"); return 0; }); new Thread(task).start(); Thread.sleep(250); task.cancel(true); System.out.println("main end"); } }
運行結果
main start
start 正在執行子任務
main end
發現子任務確實運行運行了一般,然后被取消了.
補充上一篇講到了ThreadPoolExecutor,我們在執行任務的時候只使用了execute,這個是沒有返回值的.而且如果任務拋出異常,則會直接在主線程打印出錯誤堆棧的.其實ThreadPoolExecutor還有另外一個提交任務的方法,就是submit(Runnable task, T result)和submit(Callable
如果覺得我的文章寫的還過得去的話,有錢就捧個錢場,沒錢給我捧個人場(幫我點贊或推薦一下)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69971.html
摘要:本文首發于一世流云的專欄一模式簡介模式是多線程設計模式中的一種常見模式,它的主要作用就是異步地執行任務,并在需要的時候獲取結果。二中的模式在多線程基礎之模式中,我們曾經給出過模式的通用類關系圖。 showImg(https://segmentfault.com/img/bVbiwcx?w=1000&h=667); 本文首發于一世流云的專欄:https://segmentfault.co...
摘要:同步包裝器任何集合類使用同步包裝器都會變成線程安全的,會將集合的方法使用鎖加以保護,保證線程的安全訪問。線程池中的線程執行完畢并不會馬上死亡,而是在池中準備為下一個請求提供服務。 多線程并發修改一個數據結構,很容易破壞這個數據結構,如散列表。鎖能夠保護共享數據結構,但選擇線程安全的實現更好更容易,如阻塞隊列就是線程安全的集合。 線程安全的集合 Vector和HashTable類提供了線...
摘要:線程的啟動與銷毀都與本地線程同步。操作系統會調度所有線程并將它們分配給可用的。框架的成員主要成員線程池接口接口接口以及工具類。創建單個線程的接口與其實現類用于表示異步計算的結果。參考書籍并發編程的藝術方騰飛魏鵬程曉明著 在java中,直接使用線程來異步的執行任務,線程的每次創建與銷毀需要一定的計算機資源開銷。每個任務創建一個線程的話,當任務數量多的時候,則對應的創建銷毀開銷會消耗大量...
摘要:在這個示例中我們使用了一個單線程線程池的。在延遲消逝后,任務將會并發執行。這是并發系列教程的第一部分。第一部分線程和執行器第二部分同步和鎖第三部分原子操作和 Java 8 并發教程:線程和執行器 原文:Java 8 Concurrency Tutorial: Threads and Executors 譯者:BlankKelly 來源:Java8并發教程:Threads和Execut...
閱讀 2895·2021-11-24 09:39
閱讀 1157·2021-11-02 14:38
閱讀 4141·2021-09-10 11:26
閱讀 2743·2021-08-25 09:40
閱讀 2303·2019-08-30 15:54
閱讀 477·2019-08-30 10:56
閱讀 2738·2019-08-26 12:14
閱讀 3211·2019-08-26 12:13