|
| 1 | +--- |
| 2 | +layout:pattern |
| 3 | +title:Async Method Invocation |
| 4 | +folder:async-method-invocation |
| 5 | +permalink:/patterns/async-method-invocation/ |
| 6 | +categories:Concurrency |
| 7 | +tags: |
| 8 | + -Reactive |
| 9 | +--- |
| 10 | + |
| 11 | +##作用 |
| 12 | + |
| 13 | +异步方法是一种调用线程在等待任务结果时候不会被阻塞的模式。该模式提供了对多个任务的并行处理,并通过回调或等待,在所有任务完成后在提供结果读取。 |
| 14 | + |
| 15 | +##解释 |
| 16 | + |
| 17 | +真实世界案例 |
| 18 | + |
| 19 | +>发射太空火箭是一项令人兴奋的事业。在任务指挥部下达发射命令后, 经过一些未确定的时间,火箭要么成功发射,要么重演挑战者悲剧。 |
| 20 | +
|
| 21 | +简而言之 |
| 22 | + |
| 23 | +>异步方法调用开始任务处理并,在任务结果准备好之前立即返回。任务处理的结果会在稍后再返回给调用者。 |
| 24 | +
|
| 25 | +维基百科的解释 |
| 26 | + |
| 27 | +>在多线程计算机编程中,异步方法调用(AMI),也被称为异步方法调用或异步模式。这是一种设计模式,在这种模式下,调用点在等待被调用代码完成时不会被阻塞。相反,当返回点到达时,调用线程会得到通知。轮询结果是一种不受欢迎的选择。 |
| 28 | +
|
| 29 | +**编程示例** |
| 30 | + |
| 31 | +在这个例子中,我们正在发射太空火箭和部署月球车。 |
| 32 | + |
| 33 | +该应用演示了异步方法调用模式。该模式的关键部分是`AsyncResult`,它是一个异步计算值的中间容器,`AsyncCallback` 可以在任务完成时提供执行行动作,`AsyncExecutor` 负责管理异步任务的执行。 |
| 34 | + |
| 35 | +```java |
| 36 | +publicinterfaceAsyncResult<T> { |
| 37 | +booleanisCompleted(); |
| 38 | +TgetValue()throwsExecutionException; |
| 39 | +voidawait()throwsInterruptedException; |
| 40 | +} |
| 41 | +``` |
| 42 | + |
| 43 | +```java |
| 44 | +publicinterfaceAsyncCallback<T> { |
| 45 | +voidonComplete(Tvalue,Optional<Exception>ex); |
| 46 | +} |
| 47 | +``` |
| 48 | + |
| 49 | +```java |
| 50 | +publicinterfaceAsyncExecutor { |
| 51 | +<T>AsyncResult<T>startProcess(Callable<T>task); |
| 52 | +<T>AsyncResult<T>startProcess(Callable<T>task,AsyncCallback<T>callback); |
| 53 | +<T>TendProcess(AsyncResult<T>asyncResult)throwsExecutionException,InterruptedException; |
| 54 | +} |
| 55 | +``` |
| 56 | + |
| 57 | +`ThreadAsyncExecutor` 是`AsyncExecutor` 的一个实现。接下来将着重说明它的一些关键部分。 |
| 58 | + |
| 59 | +```java |
| 60 | +publicclassThreadAsyncExecutorimplementsAsyncExecutor { |
| 61 | + |
| 62 | +@Override |
| 63 | +public<T>AsyncResult<T>startProcess(Callable<T>task) { |
| 64 | +return startProcess(task,null); |
| 65 | + } |
| 66 | + |
| 67 | +@Override |
| 68 | +public<T>AsyncResult<T>startProcess(Callable<T>task,AsyncCallback<T>callback) { |
| 69 | +var result=newCompletableResult<>(callback); |
| 70 | +newThread( |
| 71 | + ()-> { |
| 72 | +try { |
| 73 | + result.setValue(task.call()); |
| 74 | + }catch (Exception ex) { |
| 75 | + result.setException(ex); |
| 76 | + } |
| 77 | + }, |
| 78 | +"executor-"+ idx.incrementAndGet()) |
| 79 | + .start(); |
| 80 | +return result; |
| 81 | + } |
| 82 | + |
| 83 | +@Override |
| 84 | +public<T>TendProcess(AsyncResult<T>asyncResult) |
| 85 | +throwsExecutionException,InterruptedException { |
| 86 | +if (!asyncResult.isCompleted()) { |
| 87 | + asyncResult.await(); |
| 88 | + } |
| 89 | +return asyncResult.getValue(); |
| 90 | + } |
| 91 | +} |
| 92 | +``` |
| 93 | + |
| 94 | +然后我们准备发射一些火箭,看看所有东西是如何一起运作的。 |
| 95 | + |
| 96 | +```java |
| 97 | +publicstaticvoid main(String[] args) throwsException { |
| 98 | +// construct a new executor that will run async tasks |
| 99 | +var executor=newThreadAsyncExecutor(); |
| 100 | + |
| 101 | +// start few async tasks with varying processing times, two last with callback handlers |
| 102 | +finalvar asyncResult1= executor.startProcess(lazyval(10,500)); |
| 103 | +finalvar asyncResult2= executor.startProcess(lazyval("test",300)); |
| 104 | +finalvar asyncResult3= executor.startProcess(lazyval(50L,700)); |
| 105 | +finalvar asyncResult4= executor.startProcess(lazyval(20,400), callback("Deploying lunar rover")); |
| 106 | +finalvar asyncResult5= |
| 107 | + executor.startProcess(lazyval("callback",600), callback("Deploying lunar rover")); |
| 108 | + |
| 109 | +// emulate processing in the current thread while async tasks are running in their own threads |
| 110 | +Thread.sleep(350);// Oh boy, we are working hard here |
| 111 | + log("Mission command is sipping coffee"); |
| 112 | + |
| 113 | +// wait for completion of the tasks |
| 114 | +finalvar result1= executor.endProcess(asyncResult1); |
| 115 | +finalvar result2= executor.endProcess(asyncResult2); |
| 116 | +finalvar result3= executor.endProcess(asyncResult3); |
| 117 | + asyncResult4.await(); |
| 118 | + asyncResult5.await(); |
| 119 | + |
| 120 | +// log the results of the tasks, callbacks log immediately when complete |
| 121 | + log("Space rocket <"+ result1+"> launch complete"); |
| 122 | + log("Space rocket <"+ result2+"> launch complete"); |
| 123 | + log("Space rocket <"+ result3+"> launch complete"); |
| 124 | +} |
| 125 | +``` |
| 126 | + |
| 127 | +以下是控制台输出。 |
| 128 | + |
| 129 | +```java |
| 130 | +21:47:08.227 [executor-2]INFOcom.iluwatar.async.method.invocation.App-Space rocket<test> launched successfully |
| 131 | +21:47:08.269 [main]INFOcom.iluwatar.async.method.invocation.App-Mission command is sipping coffee |
| 132 | +21:47:08.318 [executor-4]INFOcom.iluwatar.async.method.invocation.App-Space rocket<20> launched successfully |
| 133 | +21:47:08.335 [executor-4]INFOcom.iluwatar.async.method.invocation.App-Deploying lunar rover<20> |
| 134 | +21:47:08.414 [executor-1]INFOcom.iluwatar.async.method.invocation.App-Space rocket<10> launched successfully |
| 135 | +21:47:08.519 [executor-5]INFOcom.iluwatar.async.method.invocation.App-Space rocket<callback> launched successfully |
| 136 | +21:47:08.519 [executor-5]INFOcom.iluwatar.async.method.invocation.App-Deploying lunar rover<callback> |
| 137 | +21:47:08.616 [executor-3]INFOcom.iluwatar.async.method.invocation.App-Space rocket<50> launched successfully |
| 138 | +21:47:08.617 [main]INFOcom.iluwatar.async.method.invocation.App-Space rocket<10> launch complete |
| 139 | +21:47:08.617 [main]INFOcom.iluwatar.async.method.invocation.App-Space rocket<test> launch complete |
| 140 | +21:47:08.618 [main]INFOcom.iluwatar.async.method.invocation.App-Space rocket<50> launch complete |
| 141 | +``` |
| 142 | + |
| 143 | +##类图 |
| 144 | + |
| 145 | + |
| 146 | + |
| 147 | +##适用性 |
| 148 | + |
| 149 | +在以下场景可以使用异步调用模式 |
| 150 | + |
| 151 | +* 你有多有可以并行执行的独立任务 |
| 152 | +* 你需要提高一组串行任务的性能 |
| 153 | +* 你的处理能力有限、或者有长期运行的任务,调用者不应该等待任务所有任务运行结束 |
| 154 | + |
| 155 | +##现实示例 |
| 156 | + |
| 157 | +*[FutureTask](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/FutureTask.html) |
| 158 | +*[CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) |
| 159 | +*[ExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html) |
| 160 | +*[Task-based Asynchronous Pattern](https://msdn.microsoft.com/en-us/library/hh873175.aspx) |
| 161 | + |