摘要:并且線(xiàn)程可被中斷,那么在訂單處理過(guò)程中接收的取消請(qǐng)求會(huì)結(jié)束剩余的處理流程。演示可取消任務(wù)的股票交易處理程序交易訂單創(chuàng)建數(shù)量為的線(xiàn)程池來(lái)執(zhí)行訂單。邪惡線(xiàn)程邪惡線(xiàn)程,隨機(jī)的取消某些訂單。判斷是否取消成功,在每?jī)蓚€(gè)請(qǐng)求之間讓邪惡線(xiàn)程睡一會(huì)。
FutureTask類(lèi)
重點(diǎn)是那個(gè)股票交易處理程序的例子,認(rèn)真看三遍。本文花了三個(gè)小時(shí)。
GitHub代碼歡迎star。
小白認(rèn)為學(xué)習(xí)語(yǔ)言最好的方式就是模仿、思考別人為什么這么寫(xiě)。
FutureTask類(lèi)同時(shí)實(shí)現(xiàn)類(lèi)Runnable接口和Future接口。因此,F(xiàn)utureTask類(lèi)技能擁有Runnable接口提供的異步計(jì)算能力,也能擁有Future接口提供的返回值給調(diào)用方的Future對(duì)象取消任務(wù)的能力。FutureTask類(lèi)可以用于封裝Callable和Runnable接口。
//Futurefuture = executor.submit(Callable); FutureTask future = new FutureTaks (Callable); future.run()
run方法會(huì)調(diào)用任務(wù),并將任務(wù)的計(jì)算結(jié)果賦值給Future對(duì)象。
也可以將FutureTask實(shí)例交給Executor對(duì)象用于執(zhí)行。
executor.submit(future);
由于FutureTask類(lèi)也實(shí)現(xiàn)了Future接口,因此FutureTak接口實(shí)例可以用來(lái)取消任務(wù),檢查任務(wù)等。
創(chuàng)建可取消的任務(wù)。取消任務(wù)可以使用執(zhí)行器返回的Future對(duì)象,而創(chuàng)建和執(zhí)行任務(wù)可以使用前面討論的FutureTask類(lèi)。
開(kāi)發(fā)可以處理上百萬(wàn)次請(qǐng)求的模擬器。會(huì)發(fā)送數(shù)千條數(shù)據(jù)交易請(qǐng)求給模擬器。模擬器包含的線(xiàn)程池用于處理這些請(qǐng)求。
還將編寫(xiě)一個(gè)“邪惡”的線(xiàn)程,它會(huì)隨機(jī)選擇諾干訂單,并且嘗試取消他們。如果訂單已經(jīng)執(zhí)行,取消請(qǐng)求會(huì)失敗。
如果在訂單在被分配給線(xiàn)程執(zhí)行之前接收到取消請(qǐng)求,那么訂單會(huì)被取消。如果交易訂單正在執(zhí)行。并且線(xiàn)程可被中斷,
那么在訂單處理過(guò)程中接收的取消請(qǐng)求會(huì)結(jié)束剩余的處理流程。從而取消訂單。
/** * Created by guo on 2018/2/15. * 演示可取消任務(wù)的股票交易處理程序 */ public class StocksOrderProcessor { static final int MAX_NUMBER_OF_ORDER = 1_000_000; //交易訂單 //1、創(chuàng)建數(shù)量為1000的線(xiàn)程池來(lái)執(zhí)行訂單。經(jīng)過(guò)測(cè)試1000個(gè)線(xiàn)程,CPU維持在70%-80%左右。 static private ExecutorService executor = Executors.newFixedThreadPool(1000); //2、創(chuàng)建ArrayList來(lái)保存執(zhí)行執(zhí)行訂單的引用 static private List主函數(shù)ordersToProcess = new ArrayList<>(); /** * 創(chuàng)建內(nèi)部私有類(lèi)OrderExecutor以處理訂單執(zhí)行的業(yè)務(wù)邏輯。 * OrderExecutor實(shí)現(xiàn)了Callable接口以支持異步調(diào)用。 */ public static class OrderExecutor implements Callable { int id = 0; int count = 0; //3、傳入整型變量id來(lái)記錄訂單編號(hào)。 public OrderExecutor(int id) { this.id = id; } @Override public Object call() throws Exception { try { //4、將技術(shù)設(shè)為1000,每次計(jì)數(shù)前,讓線(xiàn)程休眠一段不同的時(shí)間 while (count < 1000) { count++; //5、通過(guò)讓線(xiàn)程休眠一段不同的時(shí)間,模擬現(xiàn)實(shí)中每個(gè)訂單需要不同的處理時(shí)間。 Thread.sleep(new Random( System.currentTimeMillis() % 10).nextInt(10)); } System.out.println("Successfully executed order:" + id); } catch (Exception ex) { throw (ex); } return id; } } }
public static void main(String[] args) { System.out.printf("Submitting %d trades%n", MAX_NUMBER_OF_ORDER); //6、通過(guò)循環(huán)遍歷,提交一百萬(wàn)訂單。 for (int i = 0; i < MAX_NUMBER_OF_ORDER; i++) { submitOrder(i); } //7、創(chuàng)建“邪惡”線(xiàn)程嘗試隨機(jī)的取消某些訂單。 //每當(dāng)執(zhí)行到這里時(shí),就會(huì)創(chuàng)建一些取消請(qǐng)求,并針對(duì)待處理的訂單列表中存儲(chǔ)的Future對(duì)象執(zhí)行。 new Thread(new EvilThread(ordersToProcess)).start(); System.out.println("Cancelling a few order at random"); try { //8a、某些訂單可能已經(jīng)被處理,模擬器就會(huì)繼續(xù)處理剩余訂單。 // b、如果訂單在執(zhí)行器分配線(xiàn)程之前被取消,就將永遠(yuǎn)不會(huì)執(zhí)行。 // c、為了留有足夠的時(shí)間結(jié)束所有待處理的訂單,讓執(zhí)行器等待30秒。 executor.awaitTermination(30, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Checking status before shutdown"); int count = 0; //9a、通過(guò)循環(huán)遍歷,統(tǒng)計(jì)有多少訂單被成功取消。 // b、對(duì)于訂單中每一個(gè)Future對(duì)象,調(diào)用isCancelld方法。 // c、如果對(duì)應(yīng)的被成功取消,則方法返回true for (Future f : ordersToProcess) { if (f.isCancelled()) { count++; } } System.out.printf("%d trades cancelled%n", count); //10、立即停止執(zhí)行器釋放分配的所有資源 (貌似我的百萬(wàn)訂單根本停不下來(lái)啊,求解?。? executor.shutdownNow(); } private static void submitOrder(int id) { //6、a 創(chuàng)建一個(gè)Callable實(shí)例,每個(gè)實(shí)例都有為一個(gè)的Id供跟蹤 Callable邪惡線(xiàn)程callable = new OrderExecutor(id); //6、b 調(diào)用ExecutorService的submit方法可將創(chuàng)建的任務(wù)提交以待執(zhí)行。 //并且將submit方法返回的對(duì)象放到待處理訂單的數(shù)組里列表中。 ordersToProcess.add(executor.submit(callable)); }
/** * 邪惡線(xiàn)程,隨機(jī)的取消某些訂單。 */ class EvilThread implements Runnable { private ListordersToProcess; //1、在構(gòu)造函數(shù)中傳入待處理的訂單列表,這樣可以對(duì)某一些Future對(duì)象發(fā)送取消請(qǐng)求。 public EvilThread(List future) { this.ordersToProcess = future; } @Override public void run() { //2、創(chuàng)建100個(gè)取消請(qǐng)求 Random myNextKill = new Random(System.currentTimeMillis() % 100); for (int i = 0; i < 100; i++) { //3、隨機(jī)選擇Future對(duì)象進(jìn)行取消。 int index = myNextKill.nextInt(StocksOrderProcessor.MAX_NUMBER_OF_ORDER); //4、調(diào)用Future對(duì)象的cancel方法以發(fā)送請(qǐng)求,并將cancel方法的參數(shù)設(shè)為ture。表示任務(wù)可能會(huì)在執(zhí)行過(guò)程中被中斷。 boolean cancel = ordersToProcess.get(index).cancel(true); //5、判斷是否取消成功, if (cancel) { System.out.println("Cancel Order Succeded:" + index); } else { System.out.println("cancel Order Failed:" + index); } try { //6、在每?jī)蓚€(gè)請(qǐng)求之間讓“邪惡”線(xiàn)程睡一會(huì)。 Thread.sleep(myNextKill.nextInt(100)); } catch (InterruptedException e) { e.printStackTrace(); } } } }
程序運(yùn)行后部分輸出如下:
Submitting 1000000 trades Successfully executed order:28 Successfully executed order:380 Successfully executed order:288 Successfully executed order:120 Cancelling a few order at random Successfully executed order:116 Successfully executed order:1004 Successfully executed order:1005 Cancel Order Succeded:698021 cancel Order Failed:98832(重點(diǎn)) ... Successfully executed order:12268 Successfully executed order:12420 Successfully executed order:13190 Successfully executed order:12199 Checking status before shutdown 99 trades cancelled(重點(diǎn)) Successfully executed order:14045 //估計(jì)Kill線(xiàn)程太多了,遺漏這個(gè)了.求解.
從輸出可以看到:
訂單698021被成功取消,這個(gè)訂單還未執(zhí)行,
訂單98832的取消請(qǐng)求失敗了,因?yàn)檫@個(gè)訂單已經(jīng)執(zhí)行結(jié)束.
在發(fā)送的100個(gè)請(qǐng)請(qǐng)求中,有99個(gè)被成功取下.也可能是100%,取決你的電腦配置.
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/68496.html
摘要:本文首發(fā)于一世流云的專(zhuān)欄一模式簡(jiǎn)介模式是多線(xiàn)程設(shè)計(jì)模式中的一種常見(jiàn)模式,它的主要作用就是異步地執(zhí)行任務(wù),并在需要的時(shí)候獲取結(jié)果。二中的模式在多線(xiàn)程基礎(chǔ)之模式中,我們?cè)?jīng)給出過(guò)模式的通用類(lèi)關(guān)系圖。 showImg(https://segmentfault.com/img/bVbiwcx?w=1000&h=667); 本文首發(fā)于一世流云的專(zhuān)欄:https://segmentfault.co...
摘要:與基于數(shù)組的隊(duì)列相同,重載的構(gòu)造函數(shù)可以接受集合指定的初始值。這種隊(duì)列比基于數(shù)組阻塞隊(duì)列具有更高的吞吐量。創(chuàng)建個(gè)交易者實(shí)例,將自己出售的訂單放入隊(duì)列中,每個(gè)出售訂單都將會(huì)有隨機(jī)的交易量。要使用基于優(yōu)先級(jí)的隊(duì)列,需要提供適當(dāng)?shù)谋容^器。 阻塞隊(duì)列 在阻塞隊(duì)列的幫助下,許多同步問(wèn)題都可以被公式化。阻塞隊(duì)列是隊(duì)列,當(dāng)線(xiàn)程試圖對(duì)空隊(duì)列進(jìn)行出列操作,或試圖向滿(mǎn)的隊(duì)列中插入條目時(shí),隊(duì)列就會(huì)阻塞。直到...
摘要:使用進(jìn)行并行編程在中進(jìn)行并行編程最常用的方式是繼承類(lèi)或者實(shí)現(xiàn)接口。從開(kāi)始提供了和兩個(gè)接口,通過(guò)使用它們可以在任務(wù)執(zhí)行完畢后得到執(zhí)行結(jié)果。 使用Callable、Future進(jìn)行并行編程 在Java中進(jìn)行并行編程最常用的方式是繼承Thread類(lèi)或者實(shí)現(xiàn)Runnable接口。這兩種方式的缺點(diǎn)是在任務(wù)完成后無(wú)法直接獲取執(zhí)行結(jié)果,必須通過(guò)共享變量或線(xiàn)程間通信,使用起來(lái)很不方便。從Java 1....
摘要:類(lèi)重點(diǎn)是那個(gè)病毒掃描程序的例子,認(rèn)真看三遍。會(huì)從線(xiàn)程池中選擇線(xiàn)程,并將對(duì)象提交給線(xiàn)程任務(wù)。比如病毒掃描,你可以使用類(lèi)實(shí)現(xiàn)的執(zhí)行器服務(wù),每小時(shí)運(yùn)行一次病毒掃描。該應(yīng)用是以固定頻率執(zhí)行的病毒掃描程序。 Executors類(lèi) 重點(diǎn)是那個(gè)病毒掃描程序的例子,認(rèn)真看三遍。本文花了四個(gè)小時(shí)。 GitHub代碼歡迎star。 小白認(rèn)為學(xué)習(xí)語(yǔ)言最好的方式就是模仿、思考別人為什么這么寫(xiě)。結(jié)合栗子效果更好...
摘要:有三種狀態(tài)運(yùn)行關(guān)閉終止。類(lèi)類(lèi),提供了一系列工廠方法用于創(chuàng)建線(xiàn)程池,返回的線(xiàn)程池都實(shí)現(xiàn)了接口。線(xiàn)程池的大小一旦達(dá)到最大值就會(huì)保持不變,在提交新任務(wù),任務(wù)將會(huì)進(jìn)入等待隊(duì)列中等待。此線(xiàn)程池支持定時(shí)以及周期性執(zhí)行任務(wù)的需求。 這是java高并發(fā)系列第19篇文章。 本文主要內(nèi)容 介紹Executor框架相關(guān)內(nèi)容 介紹Executor 介紹ExecutorService 介紹線(xiàn)程池ThreadP...
閱讀 863·2021-11-09 09:47
閱讀 1694·2019-08-30 15:44
閱讀 1223·2019-08-26 13:46
閱讀 2193·2019-08-26 13:41
閱讀 1391·2019-08-26 13:32
閱讀 3861·2019-08-26 10:35
閱讀 3619·2019-08-23 17:16
閱讀 532·2019-08-23 17:07