From 7eb35d9da834536269678f8e02db9c553259c26e Mon Sep 17 00:00:00 2001 From: Joe <736777445@qq.com> Date: Fri, 5 Apr 2019 14:34:05 +0800 Subject: [PATCH] =?UTF-8?q?Update=2080.=20executor=20=E3=80=81task=20?= =?UTF-8?q?=E5=92=8C=20stream=20=E4=BC=98=E5=85=88=E4=BA=8E=E7=BA=BF?= =?UTF-8?q?=E7=A8=8B.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/notes/80. executor 、task 和 stream 优先于线程.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/notes/80. executor 、task 和 stream 优先于线程.md b/docs/notes/80. executor 、task 和 stream 优先于线程.md index 53fb076..cf45e84 100644 --- a/docs/notes/80. executor 、task 和 stream 优先于线程.md +++ b/docs/notes/80. executor 、task 和 stream 优先于线程.md @@ -20,15 +20,15 @@ exec.execute(runnable); exec.shutdown(); ``` -  你可以利用 executor service 完成更多的工作。例如,可以等待完成一项特殊的任务(就如第 79 条中的 get 方法一样),你可以等待一个任务集合中的任何任务或者所有任务完成(利用 invokeAny 或者 invokeAll 方法),可以等待 executor service 优雅地完成终止(利用 awaitTermination 方法),可以在任务完成时逐个地获取这些任务的结果(利用 ExecutorCompletionService ),可以调度在某个特殊的时间段定时运行或者阶段性地运行的任务(利用 ScheduledThreadPoolExecutor ),等等。 +  你可以利用 executor service 完成更多的工作。例如,可以等待完成一项特殊的任务(就如第 79 条中的 get 方法一样),你可以等待一个任务集合中的任何任务或者所有任务完成(利用 invokeAny 或者 invokeAll 方法),可以等待 executor service 优雅地完成终止(利用 awaitTermination 方法),可以在任务完成时逐个地获取这些任务的结果(利用 ExecutorCompletionService),可以调度在某个特殊的时间段定时运行或者阶段性地运行的任务(利用 ScheduledThreadPoolExecutor),等等。 -  如果想让不止一个线程来处理来自这个队列的请求,只要调用一个不同的静态工厂,这个工厂创建了一种不同的 executor service ,称作线程池( thread pool ) 。你可以用固定或者可变数目的线程创建一个线程池。java.util.concurrent.Executors 类包含了静态工厂,能为你提供所需的大多数以 excutor 。然而,如果你想来点特别的,可以直接使用 ThreadPoolExecutor 类。这个类允许你控制线程池操作的几乎每个方面。 +  如果想让不止一个线程来处理来自这个队列的请求,只要调用一个不同的静态工厂,这个工厂创建了一种不同的 executor service ,称作线程池(thread pool ) 。你可以用固定或者可变数目的线程创建一个线程池。java.util.concurrent.Executors 类包含了静态工厂,能为你提供所需的大多数以 excutor 。然而,如果你想来点特别的,可以直接使用 ThreadPoolExecutor 类。这个类允许你控制线程池操作的几乎每个方面。   为特殊的应用程序选择 executor service 是很有技巧的。如果编写的是小程序,或者是轻量负载的服务器,使用 Executors.newCachedThreadPool 通常是个不错的选择,因为它不需要配置,并且一般情况下能够正确地完成工作。但是对于大负载的服务器来说,缓存的线程池就不是很好的选择了!在缓存的线程池中,被提交的任务没有排成队列,而是直接交给线程执行。如果没有线程可用,就创建一个新的线程。如果服务器负载得太重,以致它所有的 CPU 都完全被占用了,当有更多的任务时,就会创建更多的线程,这样只会使情况变得更糟。因此,在大负载的产品服务器中,最好使用 Executors.newFixedThreadPool ,它为你提供了一个包含固定线程数目的线程池,或者为了最大限度地控制它,就直接使用 ThreadPoolExecutor 类。 -  不仅应该尽量不要编写自己的工作队列,而且还应该尽量不直接使用线程。当直接使用线程时, Thread 是既充当工作单元,又是执行机制。在 Executor Framework 中,工作单元和执行机制是分开的。现在关键的抽象是工作单元,称作任务( task ) 。任务有两种:Runnable 及其近亲 Callable (它与 Runnable 类似,但它会返回值,并且能够抛出任意的异常) 。执行任务的通用机制是 executor service 。如果你从任务的角度来看问题,并让一个 executor service 替你执行任务,在选择适当的执行策略方面就获得了极大的灵活性。从本质上讲, Executor Framework 所做的工作是执行, Collections Framework 所做的工作是聚合(aggregation)。 +  不仅应该尽量不要编写自己的工作队列,而且还应该尽量不直接使用线程。当直接使用线程时, Thread 是既充当工作单元,又是执行机制。在 Executor Framework 中,工作单元和执行机制是分开的。现在关键的抽象是工作单元,称作任务(task) 。任务有两种:Runnable 及其近亲 Callable (它与 Runnable 类似,但它会返回值,并且能够抛出任意的异常)。执行任务的通用机制是 executor service 。如果你从任务的角度来看问题,并让一个 executor service 替你执行任务,在选择适当的执行策略方面就获得了极大的灵活性。从本质上讲, Executor Framework 所做的工作是执行, Collections Framework 所做的工作是聚合(aggregation)。   在 Java 7 中, Executor Framework 得到了扩展,它可以支持 fork-join 任务了,这些任务是通过一种称作 fork-join 池的特殊 executor 服务运行的。fork-join 任务用 ForkJoinTask 实例表示,可以被分成更小的子任务,包含 ForkJoinPool 的线程不仅要处理这些任务,还要从另一个线程中“偷”任务,以确保所有的线程保持忙碌,从而提高 CPU 使用率、提高吞吐量,并降低延迟。fork-join 任务的编写和调优是很有技巧的。并发的 stream (详见第 48 条)是在 fork join 池上编写的,我们不费什么力气就能享受到它们的性能优势,前提是假设它们正好适用于我们手边的任务。 -  Executor Framework 的完整处理方法超出了本书的讨论范围,但是有兴趣的读者可以参阅《Java Concurrency in Practice 》一书[Goetz06 ] 。 +  Executor Framework 的完整处理方法超出了本书的讨论范围,但是有兴趣的读者可以参阅《Java Concurrency in Practice》一书[Goetz06] 。