Java 异步编程最佳实践

标签: 异步 Java | 发表时间:2015-03-24 14:03 | 作者:
出处:http://colobu.com/

最近异步编程非常流行, 主要是它能够在多核系统上提高吞吐率。异步编程是一种编程方式,可以提高对UI的快速响应。 Java中的异步编程模型提供了一致性的编程模型, 可以用来在程序中支持异步。 本文讨论了在使用Java执行异步操作应该遵循的最佳实践。

原文: Best Practices of Asynchronous Programming With Java

什么是异步?为什么要用它?

异步编程提供了一个非阻塞的,事件驱动的编程模型。 这种编程模型利用系统中多核执行任务来提供并行,因此提供了应用的吞吐率。此处吞吐率是指在单位时间内所做任务的数量。 在这种编程方式下, 一个工作单元将独立于主应用线程而执行, 并且会将它的状态通知调用线程:成功,处理中或者失败。

我们需要异步来消除阻塞模型。其实异步编程模型可以使用同样的线程来处理多个请求, 这些请求不会阻塞这个线程。想象一个应用正在使用的线程正在执行任务, 然后等待任务完成才进行下一步。 log框架就是一个很好的例子:典型地你想将异常和错误日志记录到一个目标中, 比如文件,数据库或者其它类似地方。你不会让你的程序等待日志写完才执行,否则程序的响应就会受到影响。 相反,如果对log框架的调用是异步地,应用就可以并发执行其它任务而无需等待。这是一个非阻塞执行的例子。

为了在Java中实现异步,你需要使用 FutureFutureTask, 它们位于 java.util.concurrent包下. Future是一个接口而 FutureTask是它的一个实现类。实际上,如果在你的代码中使用 Future, 你的异步任务会立即执行, 并且调用线程可以得到结果 promise

下面的代码片段定义了一个包含两个方法的接口。 一个是同步方法,另外一个是异步方法。

     
1
2
3
4
5
6
7
     
import java.util.concurrent.Future;
public interface IDataManager {
// synchronous method
public String getDataSynchronously();
// asynchronous method
public Future<String> getDataAsynchronously();
}

值得注意的是回调模型的弊端就是当回调嵌套时很麻烦。

该做和不该做的

为了方便测试, 你应该在代码中将功能从多线程中隔离出来。当在Java中编写异步代码时,你应该遵循异步模型,这样调用线程就不会被阻塞。
注意构造函数不能是异步的,你不应该在构造函数中调用异步方法。当任务互相不依赖时异步方式尤其有用。当调用任务依赖被调用任务时不应该使用异步(译者按:这对异步来说无意义,因为业务上调用线程被阻塞了).

你应该在异步方法中处理异常. 你不应该为长时间的task实现异常. 一个长时间运行的任务,如果异步执行的话, 可能会比同步执行耗费更长的时间, 因为运行时要为异步执行的方法执行线程上下文的切换, 线程状态的存储等. 你也应该注意同步的异常和异步的异常有所不同。 同步异常暗示 每次程序执行到那个程序特殊状态时就会抛出异常;异步异常的跟踪则困难的多。所以同步和异步异常暗示同步或异步代码可能抛出异常(synchronous and asynchronous exceptions imply synchronous or asynchronous code in your program that might raise exceptions.)。

推荐阅读

  1. https://msdn.microsoft.com/en-us/magazine/dn818494.aspx
  2. http://docs.oracle.com/javaee/6/tutorial/doc/gkiez.html
  3. https://technology.amis.nl/2009/02/19/asynchronous-processing-in-java-applications-leveraging-those-multi-cores/
  4. http://javarevisited.blogspot.in/2015/01/how-to-use-future-and-futuretask-in-Java.html
  5. http://www.codeproject.com/Articles/562021/Asynchronous-models-and-patterns

总结

异步对于设计大规模快速响应的应用是至关重要的。异步回调模型带来了很多的好处;你可以依赖你的异步回调方法来执行昂贵的I/O操作而你的处理器可以执行其它任务。然而虽然在Java和C#中提供了异步的支持,异步编程并不总是那么容易实现。异步方式的使用要谨慎: 你应该清楚什么时候可以用和什么时候不该用。

本文中我们介绍了异步编程的概念, 以及使用Java编程需要怎么去实现. 本文也列出了使用异步编程的最佳实践。谢谢阅读。

译者增加的内容

Java 7中提供了Fork/Join框架, 可以将一个大的task分割成很多可以并行执行的小task。Java 8中parallelStream内部利用Fork/Join执行并发操作。
Reactive Extensions for .NET提供了异步和基于事件编程框架, Java中对应的是Netflix的 RxJava,你可以使用它实现CQRS和Event Sourcing模式。
Akka提供了一个分布式的,容错的,事件驱动的框架, 可以实现异步的分布式的编程。
还有Spring的 reactor也提供了高性能的事件驱动的异步框架。
像Node.js天生支持异步编程模式, 其它语言如golang使用 goroutines 和 channels.也很容易实现异步。

相关 [java 异步 编程] 推荐:

Java 异步编程最佳实践

- - 鸟窝
最近异步编程非常流行, 主要是它能够在多核系统上提高吞吐率. 异步编程是一种编程方式,可以提高对UI的快速响应. Java中的异步编程模型提供了一致性的编程模型, 可以用来在程序中支持异步. 本文讨论了在使用Java执行异步操作应该遵循的最佳实践. 原文: Best Practices of Asynchronous Programming With Java.

java异步计算Future

- - 互联网 - ITeye博客
从jdk1.5开始我们可以利用Future来跟踪异步计算的结果. 在此之前主线程要想获得工作线程(异步计算线程)的结果是比较麻烦的事情,需要我们进行特殊的程序结构设计,比较繁琐而且容易出错. 有了Future我们就可以设计出比较优雅的异步计算程序结构模型:根据分而治之的思想,我们可以把异步计算的线程按照职责分为3类:.

Java编程规范

- - Web前端 - ITeye博客
本文档的编写从简,绝大多数内容以条款或者表格形式列出,不做过多的补充说明,代码格式规范遵循eclipse的默认编码规范要求. •    简单,易执行. 1.    名字含义要明确,做到见名知义,如: User,Role, UserManager. 2.    尽量使用英文名字作为变量名,如果要使用中文,请写上备注.

Java并发编程基础

- - 并发编程网 - ifeve.com
并发是一种能并行运行多个程序或并行运行一个程序中多个部分的能力. 如果程序中一个耗时的任务能以异步或并行的方式运行,那么整个程序的吞吐量和可交互性将大大改善. 现代的PC都有多个CPU或一个CPU中有多个核. 是否能合理运用多核的能力将成为一个大规模应用程序的关键. 进程是以独立于其他进程的方式运行的,进程间是互相隔离的.

java编程风格指南

- - 行业应用 - ITeye博客
受不了的可以直接到以下网址查看. 作者:Hawstein 出处:http://hawstein.com/posts/google-java-style.html 声明:本文采用以下协议进行授权: 自由转载-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0 ,转载请注明作者及出处.

面向GC的Java编程

- - 并发编程网 - ifeve.com
Java程序员在编码过程中通常不需要考虑内存问题,JVM经过高度优化的GC机制大部分情况下都能够很好地处理堆(Heap)的清理问题. 以至于许多Java程序员认为,我只需要关心何时创建对象,而回收对象,就交给GC来做吧. 甚至有人说,如果在编程过程中频繁考虑内存问题,是一种退化,这些事情应该交给编译器,交给虚拟机来解决.

java 并发编程 synchronized

- - Java - 编程语言 - ITeye博客
同步原语--synchronized. synchronized(class)很特别,它会让另一个线程在任何需要获取class做为monitor的地方等待.class与this做为不同的监视器可以同时使用,不存在一个线程获取了class,另一个线程就不能获取该class的一切实例.. ->线程各自获取monitor,不会有等待..

受禁锢的异步编程思维

- - 老赵点滴 - 追求编程之美
最近一直在努力推广 Jscex,补充了很多中文文档和示例,因此博客上都已经有两篇文章有了“上”而没有“下”,即使最复杂的图示也已经绘制完毕. 在推广Jscex的过程中,我发现有个比较明显的问题是,许多使用JavaScript的程序员已经习惯旧有的编程方式,甚至推崇一些据他们说很“漂亮”的模式. 但在我看来,这其实跟许多GoF模式是在修补OO语言的不足有些类似,很多异步模式都只是因为JavaScript语言特性不足而设计出来的“权宜之计”.

Javascript异步编程的4种方法

- - 阮一峰的网络日志
你可能知道,Javascript语言的执行环境是"单线程"(single thread). 所谓"单线程",就是指一次只能完成一件任务. 如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推. 这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行.

异步编程语言的常见坑

- - idea's blog
天生支持异步编程的语言如 NodeJS, Golang 等, 创建一个异步 routine 的成本非常小, 这确实是一个非常方便的功能. 比如用在网络爬虫程序的开发, 对于每一个要抓取的 URL 就启动一个 routine, 类似启动一个线程, 既能充分利用 CPU 多核, 代码也很简洁.. 正因为太方便, 所以常常被滥用, 并引发许多严重坑.