摘要:類被聲明在的內(nèi)部類,并且為和。構(gòu)造函數(shù)接受的整數(shù)值,并存儲(chǔ)在類變量中以備后用。該方法會(huì)創(chuàng)建固定的線程池,用于執(zhí)行不同的任務(wù),并且在結(jié)束時(shí)會(huì)返回一個(gè)實(shí)例。聲明的對(duì)象用于存儲(chǔ)對(duì)象,從而監(jiān)控提交的任務(wù)。
Callabl、Future、Executors與分支/合并框架
重點(diǎn)是那個(gè)計(jì)算年銷售額的例子,認(rèn)真看三遍。本文花了三個(gè)小時(shí)。
GitHub歡迎star。
小白認(rèn)為學(xué)習(xí)語(yǔ)言最好的方式就是模仿、思考別人為什么這么寫(xiě)。
19.1 Callable和Future接口創(chuàng)建線程要么是實(shí)現(xiàn)Runnable接口,要么實(shí)現(xiàn)Thread類繼承。雖然這么做很簡(jiǎn)單,但創(chuàng)建出的線程會(huì)受到嚴(yán)重的限制--run方法不返回任何值給創(chuàng)建者。因此,許多程序員采用將返回值寫(xiě)到文件中這樣的不完美解決方案。Runnable的另一個(gè)問(wèn)題在于不能拋出任何異常,因此必須在run方法中處理所有的異常。幸運(yùn)的是,J2SE5提供了Callable和Future接口,用于解決此類的需求,Thread模擬了一類 沒(méi)有返回結(jié)果的任務(wù)的執(zhí)行, 而Callable則是模擬 具有返回結(jié)果的任務(wù)的執(zhí)行。 Future更進(jìn)一步,模擬一類 可檢查進(jìn)度并可以取回結(jié)果的任務(wù)的執(zhí)行
19.1.1 Callable接口CCallable接口類似于Runnable接口,擁有接受單個(gè)參數(shù)的call方法。
public interface Callable{ V call() throws Exception }
call方法可以返回類型參數(shù)中指定的任意類型。需要注意的是,call方法和Runnable接口中的run方法并不相同,這里的call方法會(huì)拋出被檢查的異常。使用Callable
不能直接將Callable提交到Thread中執(zhí)行,而是必須使用ExecutorService來(lái)執(zhí)行Callable對(duì)象。,可以通過(guò)調(diào)用submit方法來(lái)完成這項(xiàng)任務(wù)。
Future submit (Callable task)
submit方法返回一個(gè)Future對(duì)象
19.1.2 Future接口當(dāng)調(diào)用方法將任務(wù)提交到Executor時(shí),Executor會(huì)返回Future對(duì)象給調(diào)用方,F(xiàn)uture接口的定義如下;
interface Future
其中V代表的是Future中g(shù)et方法返回值類型。調(diào)用方通過(guò)這個(gè)Future對(duì)象獲取所請(qǐng)求任務(wù)的控制權(quán)。get方法會(huì)將結(jié)果返回給調(diào)用方。如果計(jì)算沒(méi)有結(jié)束,get方法則會(huì)一直等下去,重載的get方法可以接受時(shí)限參數(shù),從而限制任務(wù)的最長(zhǎng)執(zhí)行時(shí)間。isDone方法檢測(cè)熱恩物是否執(zhí)行結(jié)束,如果結(jié)束,就返回true。cancel方法會(huì)在任務(wù)正常結(jié)束之前嘗試取消,如果任務(wù)正常結(jié)束之前被取消,isCancelled會(huì)返回true
FutureTask是封裝類實(shí)現(xiàn)類Future與Runnable接口,并提供了一種便捷的方式,可以將Callable轉(zhuǎn)為Future與Runnable。
Caller是實(shí)現(xiàn)類Callable接口的Java類。Callable接口僅含有call方法,程序員在實(shí)現(xiàn)Callable接口時(shí)必須實(shí)現(xiàn)call方法。call方法通常會(huì)包含服務(wù)實(shí)現(xiàn)。要調(diào)用服務(wù)就必須實(shí)例化Caller類并調(diào)用call方法。如果希望上述過(guò)程異步完成,就需要采用某些特定機(jī)制調(diào)用call方法。Callbale接口和Runnable接口不同,后者可以放在Thread類的構(gòu)造函數(shù)中執(zhí)行,Java提供了另一個(gè)名為ExecutorService的類用于執(zhí)行可調(diào)用任務(wù)。調(diào)用方首先創(chuàng)建或獲取ExecutorServie實(shí)例,并提交可調(diào)用任務(wù)以待執(zhí)行。接下來(lái)框架會(huì)返回Future對(duì)象給調(diào)用方,這個(gè)Future隊(duì)形可以用于檢查可調(diào)用任務(wù)的狀態(tài)并獲取執(zhí)行結(jié)果。
重點(diǎn)知識(shí)在main函數(shù)中
/** * Created by guo on 2018/2/15. * 計(jì)算年銷售額 */ public class AnnualSalesCalc { private static int NUMBER_OF_CUSTOMERS = 100; //表示矩陣的行數(shù) private static int NUMBER_OF_MONTHS = 12; //表示矩陣的列數(shù) private static int salesMatrix[][]; //代表尚未創(chuàng)建的二維整形數(shù)組。 /** * Summer用來(lái)計(jì)算每行的和。 * Summer類被聲明在AnnualSalesCalc的內(nèi)部類,并且為private和static。 * 之所以聲明為private,是因?yàn)镾ummer類不會(huì)用在其他地方。 * 聲明為靜態(tài)是應(yīng)為Summer類會(huì)被靜態(tài)的main方法調(diào)用。Summer類還實(shí)現(xiàn)類Callable接口。 * 構(gòu)造函數(shù)接受ID的整數(shù)值,并存儲(chǔ)在類變量中以備后用。 */ private static class Summer implements Callable { private int companyID; public Summer(int companyID) { this.companyID = companyID; } /** * Call方法被映射為任何類型的泛型類,在這里被映射為Integer類型 * call方法通過(guò)for循環(huán)遍歷來(lái)計(jì)算矩陣特定行內(nèi)的所有元素的總和 */ public Integer call() throws Exception { int sum = 0; // for (int col = 0; col < NUMBER_OF_MONTHS; col++) { sum += salesMatrix[companyID][col]; } //在求和計(jì)算完成之后,程序會(huì)打印一條消息給用戶, // 表明這個(gè)Callable對(duì)象的任務(wù)已經(jīng)結(jié)束,并且無(wú)論什么時(shí)候被詢問(wèn),都可以將計(jì)算結(jié)果返回給調(diào)用者。 System.out.printf("Totaling for client 1%02d completed%n", companyID); return sum; } } public static void main(String[] args) throws Exception { generateMatrix(); printMaxtrix(); //我們需要執(zhí)行者服務(wù)調(diào)用Callable對(duì)象,Executor類提供此服務(wù) //newFixedThreadPool是Executors類的靜態(tài)方法,接受一個(gè)整型參數(shù), //該參數(shù)的值決定了這個(gè)方法創(chuàng)建的線程數(shù)目。 //該方法會(huì)創(chuàng)建固定的線程池,用于執(zhí)行不同的任務(wù),并且在結(jié)束時(shí)會(huì)返回一個(gè)ExecutorService實(shí)例。 ExecutorService executor = Executors.newFixedThreadPool(10); //聲明的Set對(duì)象用于存儲(chǔ)Future對(duì)象,從而監(jiān)控提交的任務(wù)。 Set> set = new HashSet >(); for (int row = 0; row < NUMBER_OF_CUSTOMERS; row++) { //為矩陣的每一行都實(shí)例化類Summer對(duì)象,Summer對(duì)象同時(shí)也是Callable對(duì)象 Callable callable = new Summer(row); //通過(guò)調(diào)用前面創(chuàng)建的executor對(duì)象的submit方法來(lái)運(yùn)行這個(gè)Callable對(duì)象; //submit方法將Callable對(duì)象提交給線程池中的某一個(gè)線程,并返回一個(gè)Future對(duì)象給調(diào)用者。 //調(diào)用方可以使用這個(gè)Future對(duì)象的get方法來(lái)獲取計(jì)算結(jié)果。 Future future = executor.submit(callable); //我們將返回的Future對(duì)象放在集合中,以便在最后階段獲取集合中所有元素之和,進(jìn)而計(jì)算總和 set.add(future); } int sum = 0; //在提交 所有任務(wù)之后,使用for-each循環(huán)計(jì)算總和 for (Future future : set) { sum += future.get(); } System.out.printf("%n The annual turnover (bags) : %s%n%n", sum); //最后關(guān)閉執(zhí)行者服務(wù),以釋放分配的所有資源。 executor.shutdown(); } }
為了清晰,我把這兩個(gè)方法從類中拿出來(lái)了。
/** * 生成矩陣 */ 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++) { //數(shù)組中的每個(gè)元素都被初始化為0-99之間的隨機(jī)數(shù)。 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
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/76313.html
摘要:這時(shí)候還是要記得貼作品網(wǎng)址,如果說(shuō)上面貼的業(yè)余時(shí)間作品是你理想主義的實(shí)現(xiàn),那么工作的作品能很好的說(shuō)明所在公司的開(kāi)發(fā)流程下的妥協(xié)實(shí)現(xiàn),如何在設(shè)計(jì)與后臺(tái)數(shù)據(jù)之間取得平衡,如果在產(chǎn)品與設(shè)計(jì)之間找到爆發(fā)點(diǎn)。 文章背景:結(jié)束d2之行或周末的前端群線下見(jiàn)面會(huì),跟一些待畢業(yè)的學(xué)生或正在這個(gè)行業(yè)的從業(yè)者交流后我深切的感觸到:在如今信息大爆炸的今天,搜索引擎這么方便的前提下,除了少部分乘上校招快車的幸運(yùn)...
摘要:這時(shí)候還是要記得貼作品網(wǎng)址,如果說(shuō)上面貼的業(yè)余時(shí)間作品是你理想主義的實(shí)現(xiàn),那么工作的作品能很好的說(shuō)明所在公司的開(kāi)發(fā)流程下的妥協(xié)實(shí)現(xiàn),如何在設(shè)計(jì)與后臺(tái)數(shù)據(jù)之間取得平衡,如果在產(chǎn)品與設(shè)計(jì)之間找到爆發(fā)點(diǎn)。 文章背景:結(jié)束d2之行或周末的前端群線下見(jiàn)面會(huì),跟一些待畢業(yè)的學(xué)生或正在這個(gè)行業(yè)的從業(yè)者交流后我深切的感觸到:在如今信息大爆炸的今天,搜索引擎這么方便的前提下,除了少部分乘上校招快車的幸運(yùn)...
摘要:這時(shí)候還是要記得貼作品網(wǎng)址,如果說(shuō)上面貼的業(yè)余時(shí)間作品是你理想主義的實(shí)現(xiàn),那么工作的作品能很好的說(shuō)明所在公司的開(kāi)發(fā)流程下的妥協(xié)實(shí)現(xiàn),如何在設(shè)計(jì)與后臺(tái)數(shù)據(jù)之間取得平衡,如果在產(chǎn)品與設(shè)計(jì)之間找到爆發(fā)點(diǎn)。 文章背景:結(jié)束d2之行或周末的前端群線下見(jiàn)面會(huì),跟一些待畢業(yè)的學(xué)生或正在這個(gè)行業(yè)的從業(yè)者交流后我深切的感觸到:在如今信息大爆炸的今天,搜索引擎這么方便的前提下,除了少部分乘上校招快車的幸運(yùn)...
摘要:被洗腦裸辭學(xué)大專學(xué)的是數(shù)控技術(shù),畢業(yè)后進(jìn)了一家公司,從事跟數(shù)控相關(guān)的工作,收入太低了一直想要換工作。裸辭學(xué)習(xí),上海的高消費(fèi)讓我負(fù)債累累,然而這種孤注一擲并沒(méi)有獲得好的結(jié)果。 ...
閱讀 1732·2021-09-26 09:55
閱讀 5694·2021-09-22 15:40
閱讀 2075·2019-08-30 15:53
閱讀 1547·2019-08-30 11:15
閱讀 1768·2019-08-29 15:41
閱讀 1928·2019-08-28 18:13
閱讀 3209·2019-08-26 12:00
閱讀 1724·2019-08-26 10:30