Tips
书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code
注意,书中的有些代码里方法是基于Java 9 API中的,因此JDK 最好下载 JDK 9以上的版本。java
本书的初版包含一个简单工做队列的代码[Bloch01,条目 49]。 此类容许客户端将后台线程的异步处理工做排入队列。 当再也不须要工做队列时,客户端能够调用一个方法,要求后台线程在完成队列中已有的任何工做后正常终止自身。 实现只不过是个玩具,但即使如此,它还须要一整页精细,细致的代码,若是你没有恰到好处的话,这种代码很容易出现安全和活性失败。 幸运的是,没有理由再编写这种代码了。git
到本书第二版出版时,java.util.concurrent包已添加到Java中。 该包包含一个Executor Framework,它是一个灵活的基于接口的任务执行工具。 建立一个比本书初版更好的工做队列只须要一行代码:github
ExecutorService exec = Executors.newSingleThreadExecutor();
下面是如何提交一个可运行的(runnable)执行:小程序
exec.execute(runnable);
下面是如何告诉executor优雅地终止(若是作不到这一点,你的虚拟机极可能不会退出):缓存
exec.shutdown();
可使用执行器服务(executor service)作更多的事情。例如,能够等待一个特定任务完成(条目 79中使用get方法, 319页),能够等待任何或所有任务完成的集合(使用invokeAny或invokeAll方法),也能够等待执行者服务终止(使用awaitTermination方法),能够在完成任务时逐个检索任务结果(使用ExecutorCompletionService),能够安排任务在特定时间运行或按期运行(使用ScheduledThreadPoolExecutor),等等。安全
若是但愿多个线程处理来自队列的请求,只需调用另外一个静态工厂,该工厂建立一种称为线程池的不一样类型的执行器服务。 能够建立具备固定或可变数量线程的线程池。 java.util.concurrent.Executors类包含静态工厂,它们提供了你须要的大多数执行程序。 可是,若是想要一些不同凡响的东西,能够直接使用ThreadPoolExecutor类。 此类容许你配置线程池操做的几乎每一个方面。服务器
为特定应用程序选择执行程序服务可能很棘手。 对于小程序或负载较轻的服务器,Executors.newCachedThreadPool
一般是一个不错的选择,由于它不须要配置,一般“作正确的事情”。可是对于负载很重的生产服务器来讲,缓存线程池不是一个好的选择! 在缓存线程池中,提交的任务不会排队,而是当即传递给线程执行。 若是没有可用的线程,则建立一个新线程。 若是服务器负载太重以致于全部CPU都被充分利用而且更多任务到达时,则会建立更多线程,这只会使事情变得更糟。 所以,在负载很重的生产服务器中,最好使用Executors.newFixedThreadPool
,它提供具备固定线程数的池,或直接使用ThreadPoolExecutor类,以实现最大程度的控制。多线程
不只应该避免编写本身的工做队列,并且一般应该避免直接使用线程。 当直接使用Thread类时,线程既能够做为工做单元,也能够做为执行它的机制。 在executor framework中,工做单元和执行机制是分开的。 关键的抽象是工做单元,称为任务。 有两种任务:Runnable
及其近亲Callable
(相似于Runnable,除了它返回一个值而且能够抛出任意异常)。 执行任务的通常机制是executor service。 若是从任务的角度来看,让executor service为你执行它们,能够灵活地选择适当的执行策略以知足你的需求,并在需求发生变化时更改策略。 本质上本质上,Executor Framework执行的功能与Collections Framework聚合(aggregation)功能是相同的。异步
在Java 7中,Executor Framework被扩展为支持fork-join任务,这些任务由称为fork-join池的特殊executor service运行。 由ForkJoinTask实例表示的fork-join任务能够拆分为较小的子任务,而包含ForkJoinPool的线程不只处理这些任务,并且还“彼此”窃取“任务”以确保全部线程都保持忙碌,从而致使更高的任务 CPU利用率,更高的吞吐量和更低的延迟。 编写和调优fork-join任务很棘手。 并行流(Parallel streams)(条目 48)是在fork-join池之上编写的,假设它们适合当前的任务,那么你能够轻松地利用它们的性能优点。工具
对Executor Framework的完整处理超出了本书的范围,但感兴趣的读者能够参考 《Java Concurrency in Practice》一书[Goetz06]。