Java C#asynchronous/等待的等待?

我是一个普通的C#开发人员,但偶尔我用java开发应用程序。 我期待的是有任何Java相当于C#asynchronous/等待? 简单地说,java的等价物是什么,

async Task<int> AccessTheWebAsync() { HttpClient client = new HttpClient(); var urlContents = await client.GetStringAsync("http://msdn.microsoft.com"); return urlContents.Length; } 

不,在Java中甚至没有任何asynchronous/等待,甚至在v5之前的C#中。

在幕后构build状态机是一个相当复杂的语言function。

Java中asynchronous/并发的语言支持相对较less,但java.util.concurrent包中包含许多有用的 。 (不完全等同于任务并行库,但与其最接近。)

await在asynchronous操作完成时使用延续来执行额外的代码( client.GetStringAsync(...) )。

所以,作为最接近的近似,我将使用CompletableFuture<T> (与.net Task<TResult>等效的Java 8)解决scheme来asynchronous处理Http请求。

2016年4月13日发布的AsyncHttpClient v.2更新于25-05-2016:

因此,与AccessTheWebAsync()的OP示例等效的Java 8如下所示:

 CompletableFuture<Integer> AccessTheWebAsync() { AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient(); return asyncHttpClient .prepareGet("http://msdn.microsoft.com") .execute() .toCompletableFuture() .thenApply(Response::getResponseBody) .thenApply(String::length); } 

这个用法是从如何从asynchronousHttp客户端请求获得CompletableFuture的答案中得到的。 根据2016年4月13日发布的AsyncHttpClient版本2中提供的新API,对CompletableFuture<T>已经有内在的支持。

使用AsyncHttpClient版本1的原始答案:

为此,我们有两种可能的方法:

  • 第一个使用非阻塞IO,我称之为AccessTheWebAsyncNio 。 然而,因为AsyncCompletionHandler是一个抽象类(而不是函数接口),我们不能传递一个lambda作为参数。 所以它由于匿名类的语法而产生不可避免的冗长。 但是, 这个解决scheme最接近给定C#示例的执行stream程

  • 第二个稍微不详细,但它会提交一个新的任务 ,最终将阻止f.get()的线程,直到响应完成。

第一种方法 ,更详细但非阻塞:

 static CompletableFuture<Integer> AccessTheWebAsyncNio(){ final AsyncHttpClient asyncHttpClient = new AsyncHttpClient(); final CompletableFuture<Integer> promise = new CompletableFuture<>(); asyncHttpClient .prepareGet("https://msdn.microsoft.com") .execute(new AsyncCompletionHandler<Response>(){ @Override public Response onCompleted(Response resp) throws Exception { promise.complete(resp.getResponseBody().length()); return resp; } }); return promise; } 

第二种方法不详细,但阻塞一个线程:

 static CompletableFuture<Integer> AccessTheWebAsync(){ try(AsyncHttpClient asyncHttpClient = new AsyncHttpClient()){ Future<Response> f = asyncHttpClient .prepareGet("https://msdn.microsoft.com") .execute(); return CompletableFuture.supplyAsync( () -> return f.join().getResponseBody().length()); } } 

C#async / await与一个称为Fibers又名合作线程又名轻量级线程的概念相当。 在Java语言层面上,没有相当于Java的C#asynchronous/等待,但是你可以find提供对光纤支持的库。

实现Fibers的Java库

  • JetLang
  • 基里姆
  • 类星体

你可以阅读这篇文章(来自Quasar) ,了解纤维的一个很好的介绍。 它涵盖了什么线程,如何在JVM上实现光纤,并具有一些Quasar特定的代码。

asynchronous等待是语法糖。 asynchronous和等待的本质是状态机。 编译器会将asynchronous/等待代码转换成状态机。

同时,为了使asynchronous/等待在真实项目中真正实用,我们需要拥有大量的asynchronousI / O库函数 。 对于C#,大多数原始的同步I / O函数都有一个替代的asynchronous版本。 我们需要这些asynchronous函数的原因是因为在大多数情况下,你自己的asynchronous/等待代码会归结为一些库asynchronous方法。

C#中的Async版本库函数有点像Java中的AsynchronousChannel概念。 例如,我们有AsynchronousFileChannel.read,它可以在读取操作完成后返回Future或执行callback。 但不完全一样。 所有C#asynchronous函数都返回任务(类似于未来,但比未来更强大)。

所以我们假设Java支持asynchronous/等待,我们写这样的代码:

 public static async Future<Byte> readFirstByteAsync(String filePath) { Path path = Paths.get(filePath); AsynchronousFileChannel channel = AsynchronousFileChannel.open(path); ByteBuffer buffer = ByteBuffer.allocate(100_000); await channel.read(buffer, 0, buffer, this); return buffer.get(0); } 

然后我会想象编译器将原始的asynchronous/等待代码转换成这样的东西:

 public static Future<Byte> readFirstByteAsync(String filePath) { CompletableFuture<Byte> result = new CompletableFuture<Byte>(); AsyncHandler ah = new AsyncHandler(result, filePath); ah.completed(null, null); return result; } 

这里是AsyncHandler的实现:

 class AsyncHandler implements CompletionHandler<Integer, ByteBuffer> { CompletableFuture<Byte> future; int state; String filePath; public AsyncHandler(CompletableFuture<Byte> future, String filePath) { this.future = future; this.state = 0; this.filePath = filePath; } @Override public void completed(Integer arg0, ByteBuffer arg1) { try { if (state == 0) { state = 1; Path path = Paths.get(filePath); AsynchronousFileChannel channel = AsynchronousFileChannel.open(path); ByteBuffer buffer = ByteBuffer.allocate(100_000); channel.read(buffer, 0, buffer, this); return; } else { Byte ret = arg1.get(0); future.complete(ret); } } catch (Exception e) { future.completeExceptionally(e); } } @Override public void failed(Throwable arg0, ByteBuffer arg1) { future.completeExceptionally(arg0); } } 

检查了Java字节码重写的ea-async ,以非常好地模拟asynchronous/等待。 根据他们的自述文件:“它受到.NET CLR上的Async-Await的启发”

Java本身没有相应的function,但是存在提供类似function的第三方库,例如Kilim 。

如前所述,没有直接的等价物,但是可以通过对Java字节码进行修改(对于asynchronous/类似于待处理的指令和基础的继续实现)来创build非常接近的近似值。

我现在正在执行一个在JavaFlow延续库上实现asynchronous/等待的项目,请查看https://github.com/vsilaev/java-async-await

没有创buildMaven mojo,但是您可以使用提供的Java代理运行示例。 以下是async / await代码的样子:

 public class AsyncAwaitNioFileChannelDemo { public static void main(final String[] argv) throws Exception { ... final AsyncAwaitNioFileChannelDemo demo = new AsyncAwaitNioFileChannelDemo(); final CompletionStage<String> result = demo.processFile("./.project"); System.out.println("Returned to caller " + LocalTime.now()); ... } public @async CompletionStage<String> processFile(final String fileName) throws IOException { final Path path = Paths.get(new File(fileName).toURI()); try ( final AsyncFileChannel file = new AsyncFileChannel( path, Collections.singleton(StandardOpenOption.READ), null ); final FileLock lock = await(file.lockAll(true)) ) { System.out.println("In process, shared lock: " + lock); final ByteBuffer buffer = ByteBuffer.allocateDirect((int)file.size()); await( file.read(buffer, 0L) ); System.out.println("In process, bytes read: " + buffer); buffer.rewind(); final String result = processBytes(buffer); return asyncResult(result); } catch (final IOException ex) { ex.printStackTrace(System.out); throw ex; } } 

@async是将方法标记为asynchronous可执行的注释,await()是一个函数,在CompletableFuture上使用延续等待,并调用“return asyncResult(someValue)”来终止相关的CompletableFuture / Continuation

和C#一样,控制stream程被保留,exception处理可以按常规方式完成(try / catch就像顺序执行的代码一样)

java本身并没有任何东西可以让你像async / await这样做关键字,但是如果你真的想使用CountDownLatch ,你可以做什么。 然后你可以模仿asynchronous/等待通过传递(至less在Java7中)。 在Androidunit testing中,我们必须做一个asynchronous调用(通常是一个处理程序发布的runnable),然后等待结果(倒计数)。

然而,在你的应用程序中使用这个而不是你的testing是不是我所推荐的。 如果CountDownLatch依赖于你有效的倒计数和正确的地方,这将是非常低劣的。

我制作并发布了Javaasynchronous/等待库。 https://github.com/stofu1234/kamaitachi

这个库不需要编译器扩展,在Java中实现无堆栈的IO处理。

  async Task<int> AccessTheWebAsync(){ HttpClient client= new HttpClient(); var urlContents= await client.GetStringAsync("http://msdn.microsoft.com"); return urlContents.Length; } 

  //LikeWebApplicationTester.java BlockingQueue<Integer> AccessTheWebAsync() { HttpClient client = new HttpClient(); return awaiter.await( () -> client.GetStringAsync("http://msdn.microsoft.com"), urlContents -> { return urlContents.length(); }); } public void doget(){ BlockingQueue<Integer> lengthQueue=AccessTheWebAsync(); awaiter.awaitVoid(()->lengthQueue.take(), length->{ System.out.println("Length:"+length); } ); } 

Java不幸的没有相当于asynchronous/等待。 最接近的可能是来自Guava的ListenableFuture和侦听器链接,但是对于涉及多个asynchronous调用的情况,编写代码仍然非常麻烦,因为嵌套级别会很快增长。

如果你可以在JVM上使用不同的语言,幸运的是,在Scala中有asynchronous/等待,这是一个直接的C#asynchronous/等待,具有几乎相同的语法和语义: https : //github.com/scala/asynchronous/

请注意,虽然这个function需要C#中相当先进的编译器支持,但在Scala中,它可以作为一个库添加,这要归功于Scala中非常强大的macros系统,因此可以添加到旧版本的Scala中,例如2.10。 另外Scala与Java是类兼容的,所以你可以在Scala中编写asynchronous代码,然后从Java调用它。

还有另外一个类似的项目叫做Akka Dataflow http://doc.akka.io/docs/akka/2.3-M1/scala/dataflow.html ,它使用不同的措辞,但是在概念上非常相似,但是使用分隔的延续来实现,而不是macros(所以它适用于更老的Scala版本,如2.9)。

首先,了解什么是asynchronous/等待。 这是单线程GUI应用程序或高效服务器在单个线程上运行多个“光纤”或“协同例程”或“轻量级线程”的一种方式。

如果使用普通线程可以,那么Java的等价物就是ExecutorService.submitFuture.get 。 这将阻塞,直到任务完成,并返回结果。 同时,其他线程可以工作。

如果你想要像光纤这样的好处,你需要在容器(我的意思是在GUI事件循环或在服务器的HTTP请求处理程序)的支持,或者写你自己的。 例如,Servlet 3.0提供asynchronous处理。 JavaFX提供javafx.concurrent.Task 。 尽pipe如此,这些语言function还是不够优雅的。 他们通过普通的callback工作。

如果你只是在干净的代码之后,它模拟与java中的asynchronous/等待相同的效果,不介意阻塞线程,直到它完成,如在testing中,你可以使用这样的代码:

 interface Async { void run(Runnable handler); } static void await(Async async) throws InterruptedException { final CountDownLatch countDownLatch = new CountDownLatch(1); async.run(new Runnable() { @Override public void run() { countDownLatch.countDown(); } }); countDownLatch.await(YOUR_TIMEOUT_VALUE_IN_SECONDS, TimeUnit.SECONDS); } await(new Async() { @Override public void run(final Runnable handler) { yourAsyncMethod(new CompletionHandler() { @Override public void completion() { handler.run(); } }); } }); 

Java有一个名为java.util.concurrent.Future的类,它相当于C# Task类。

您可以启动一个java.util.concurrent.Executor对象的工作。 有很多的实现,但是如果你尝试这个命令的时候遇到线程限制, ForkJoinTask.fork()值得一看。

开始工作时,你会得到一个Future 。 你的方法将继续运行。 当你需要你未来的结果时,你调用get() ,它将被阻塞直到结果准备好。 这与在C#中使用await关键字类似。