摘要:類被聲明在的內部類,并且為和。構造函數接受的整數值,并存儲在類變量中以備后用。該方法會創建固定的線程池,用于執行不同的任務,并且在結束時會返回一個實例。聲明的對象用于存儲對象,從而監控提交的任務。
Callabl、Future、Executors與分支/合并框架
重點是那個計算年銷售額的例子,認真看三遍。本文花了三個小時。
GitHub歡迎star。
小白認為學習語言最好的方式就是模仿、思考別人為什么這么寫。
19.1 Callable和Future接口創建線程要么是實現Runnable接口,要么實現Thread類繼承。雖然這么做很簡單,但創建出的線程會受到嚴重的限制--run方法不返回任何值給創建者。因此,許多程序員采用將返回值寫到文件中這樣的不完美解決方案。Runnable的另一個問題在于不能拋出任何異常,因此必須在run方法中處理所有的異常。幸運的是,J2SE5提供了Callable和Future接口,用于解決此類的需求,Thread模擬了一類 沒有返回結果的任務的執行, 而Callable則是模擬 具有返回結果的任務的執行。 Future更進一步,模擬一類 可檢查進度并可以取回結果的任務的執行
19.1.1 Callable接口CCallable接口類似于Runnable接口,擁有接受單個參數的call方法。
public interface Callable{ V call() throws Exception }
call方法可以返回類型參數中指定的任意類型。需要注意的是,call方法和Runnable接口中的run方法并不相同,這里的call方法會拋出被檢查的異常。使用Callable
不能直接將Callable提交到Thread中執行,而是必須使用ExecutorService來執行Callable對象。,可以通過調用submit方法來完成這項任務。
Future submit (Callable task)
submit方法返回一個Future對象
19.1.2 Future接口當調用方法將任務提交到Executor時,Executor會返回Future對象給調用方,Future接口的定義如下;
interface Future
其中V代表的是Future中get方法返回值類型。調用方通過這個Future對象獲取所請求任務的控制權。get方法會將結果返回給調用方。如果計算沒有結束,get方法則會一直等下去,重載的get方法可以接受時限參數,從而限制任務的最長執行時間。isDone方法檢測熱恩物是否執行結束,如果結束,就返回true。cancel方法會在任務正常結束之前嘗試取消,如果任務正常結束之前被取消,isCancelled會返回true
FutureTask是封裝類實現類Future與Runnable接口,并提供了一種便捷的方式,可以將Callable轉為Future與Runnable。
Caller是實現類Callable接口的Java類。Callable接口僅含有call方法,程序員在實現Callable接口時必須實現call方法。call方法通常會包含服務實現。要調用服務就必須實例化Caller類并調用call方法。如果希望上述過程異步完成,就需要采用某些特定機制調用call方法。Callbale接口和Runnable接口不同,后者可以放在Thread類的構造函數中執行,Java提供了另一個名為ExecutorService的類用于執行可調用任務。調用方首先創建或獲取ExecutorServie實例,并提交可調用任務以待執行。接下來框架會返回Future對象給調用方,這個Future隊形可以用于檢查可調用任務的狀態并獲取執行結果。
重點知識在main函數中
/** * Created by guo on 2018/2/15. * 計算年銷售額 */ public class AnnualSalesCalc { private static int NUMBER_OF_CUSTOMERS = 100; //表示矩陣的行數 private static int NUMBER_OF_MONTHS = 12; //表示矩陣的列數 private static int salesMatrix[][]; //代表尚未創建的二維整形數組。 /** * Summer用來計算每行的和。 * Summer類被聲明在AnnualSalesCalc的內部類,并且為private和static。 * 之所以聲明為private,是因為Summer類不會用在其他地方。 * 聲明為靜態是應為Summer類會被靜態的main方法調用。Summer類還實現類Callable接口。 * 構造函數接受ID的整數值,并存儲在類變量中以備后用。 */ private static class Summer implements Callable { private int companyID; public Summer(int companyID) { this.companyID = companyID; } /** * Call方法被映射為任何類型的泛型類,在這里被映射為Integer類型 * call方法通過for循環遍歷來計算矩陣特定行內的所有元素的總和 */ public Integer call() throws Exception { int sum = 0; // for (int col = 0; col < NUMBER_OF_MONTHS; col++) { sum += salesMatrix[companyID][col]; } //在求和計算完成之后,程序會打印一條消息給用戶, // 表明這個Callable對象的任務已經結束,并且無論什么時候被詢問,都可以將計算結果返回給調用者。 System.out.printf("Totaling for client 1%02d completed%n", companyID); return sum; } } public static void main(String[] args) throws Exception { generateMatrix(); printMaxtrix(); //我們需要執行者服務調用Callable對象,Executor類提供此服務 //newFixedThreadPool是Executors類的靜態方法,接受一個整型參數, //該參數的值決定了這個方法創建的線程數目。 //該方法會創建固定的線程池,用于執行不同的任務,并且在結束時會返回一個ExecutorService實例。 ExecutorService executor = Executors.newFixedThreadPool(10); //聲明的Set對象用于存儲Future對象,從而監控提交的任務。 Set> set = new HashSet >(); for (int row = 0; row < NUMBER_OF_CUSTOMERS; row++) { //為矩陣的每一行都實例化類Summer對象,Summer對象同時也是Callable對象 Callable callable = new Summer(row); //通過調用前面創建的executor對象的submit方法來運行這個Callable對象; //submit方法將Callable對象提交給線程池中的某一個線程,并返回一個Future對象給調用者。 //調用方可以使用這個Future對象的get方法來獲取計算結果。 Future future = executor.submit(callable); //我們將返回的Future對象放在集合中,以便在最后階段獲取集合中所有元素之和,進而計算總和 set.add(future); } int sum = 0; //在提交 所有任務之后,使用for-each循環計算總和 for (Future future : set) { sum += future.get(); } System.out.printf("%n The annual turnover (bags) : %s%n%n", sum); //最后關閉執行者服務,以釋放分配的所有資源。 executor.shutdown(); } }
為了清晰,我把這兩個方法從類中拿出來了。
/** * 生成矩陣 */ private static void generateMatrix() { salesMatrix = new int[NUMBER_OF_CUSTOMERS][NUMBER_OF_MONTHS]; for (int i = 0; i < NUMBER_OF_CUSTOMERS; i++) { for (int j = 0; j < NUMBER_OF_MONTHS; j++) { //數組中的每個元素都被初始化為0-99之間的隨機數。 salesMatrix[i][j] = (int) (Math.random() * 100); } } } /** * 打印矩陣 */ private static void printMaxtrix() { System.out.print(" "); String[] monthDisplayName = new DateFormatSymbols().getShortMonths(); for (String strName : monthDisplayName) { System.out.printf("%8s", strName); } System.out.printf(" "); for (int i = 0; i < NUMBER_OF_CUSTOMERS; i++) { System.out.printf("Client ID : 1%02d", i); for (int j = 0; j < NUMBER_OF_MONTHS; j++) { System.out.printf("%8d", salesMatrix[i][j]); } System.out.println(); } System.out.println(" "); }
輸出如下:
一月 二月 三月 四月 五月 六月 七月 八月 九月 十月 十一月 十二月 Client ID : 100 89 63 98 51 1 58 69 67 81 97 98 64 Client ID : 101 66 83 3 83 75 43 10 83 92 39 27 75 Client ID : 102 10 88 74 38 33 91 43 82 93 94 28 25 ...省略.. Client ID : 197 50 39 43 33 18 61 67 21 11 56 11 19 Client ID : 198 64 5 10 63 97 52 99 35 15 9 73 29 Client ID : 199 47 95 62 51 7 78 68 60 53 58 23 56 Totaling for client 101 completed Totaling for client 102 completed Totaling for client 110 completed ...省略.. Totaling for client 105 completed Totaling for client 109 completed The annual turnover (bags) : 60152
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76313.html
摘要:這時候還是要記得貼作品網址,如果說上面貼的業余時間作品是你理想主義的實現,那么工作的作品能很好的說明所在公司的開發流程下的妥協實現,如何在設計與后臺數據之間取得平衡,如果在產品與設計之間找到爆發點。 文章背景:結束d2之行或周末的前端群線下見面會,跟一些待畢業的學生或正在這個行業的從業者交流后我深切的感觸到:在如今信息大爆炸的今天,搜索引擎這么方便的前提下,除了少部分乘上校招快車的幸運...
摘要:這時候還是要記得貼作品網址,如果說上面貼的業余時間作品是你理想主義的實現,那么工作的作品能很好的說明所在公司的開發流程下的妥協實現,如何在設計與后臺數據之間取得平衡,如果在產品與設計之間找到爆發點。 文章背景:結束d2之行或周末的前端群線下見面會,跟一些待畢業的學生或正在這個行業的從業者交流后我深切的感觸到:在如今信息大爆炸的今天,搜索引擎這么方便的前提下,除了少部分乘上校招快車的幸運...
摘要:這時候還是要記得貼作品網址,如果說上面貼的業余時間作品是你理想主義的實現,那么工作的作品能很好的說明所在公司的開發流程下的妥協實現,如何在設計與后臺數據之間取得平衡,如果在產品與設計之間找到爆發點。 文章背景:結束d2之行或周末的前端群線下見面會,跟一些待畢業的學生或正在這個行業的從業者交流后我深切的感觸到:在如今信息大爆炸的今天,搜索引擎這么方便的前提下,除了少部分乘上校招快車的幸運...
摘要:被洗腦裸辭學大專學的是數控技術,畢業后進了一家公司,從事跟數控相關的工作,收入太低了一直想要換工作。裸辭學習,上海的高消費讓我負債累累,然而這種孤注一擲并沒有獲得好的結果。 ...
閱讀 1655·2021-09-26 09:55
閱讀 5247·2021-09-22 15:40
閱讀 2012·2019-08-30 15:53
閱讀 1497·2019-08-30 11:15
閱讀 1714·2019-08-29 15:41
閱讀 1869·2019-08-28 18:13
閱讀 3145·2019-08-26 12:00
閱讀 1667·2019-08-26 10:30