使用线程池的原因
-
构建一个新的线程时有一定代价的。
-
可以减少并发线程的数目。创建大量线程会大大降低性能甚至使虚拟机崩溃。
线程池工厂方法
| 方法 | 描述 |
|---|---|
| newCachedThreadPool | 必要时创建新线程,空闲时线程会被保留60秒 |
| newFIxedThreadPool | 该池包含固定数量的线程;空闲线程会一直被保留 |
| newSingleThreadExecutor | 只有一个线程的池,该线程顺序执行每一个提交的任务 |
| newScheduledThreadPool | 用于预定执行而构建的固定线程池,替代java.util.Timer |
| newSingleThreadScheduledExecutor | 用于预定执行而构建的单线程池 |
newFIxedThreadPool
固定大小的线程池,超过的任务在队列中等待。
使用步骤
-
调用Executors类中静态的方法newCachedThreadPool或newFixedThreadPool。
-
调用submit提交Runnable或Callable对象。
-
如果想要取消一个任务,或如果提交Callable对象,就要保存好返回的Future对象
-
当不再提交任务时,调用shutdown。
预定执行
ScheduledExecutorService接口具有为预定执行或重复执行任务而设计的方法。由newScheduledThreadPool和newSingleThreadScheduledExecutor返回实现了该接口的对象。
其可以预定Runnable或Callable在初始的延迟之后只运行一次。也可以预定一个Runnable对象周期运行。
控制任务组的能力
执行器还可以控制一组相关任务。
-
ExecutorService#invokeAny方法,提交所有对象到一个Callable对象的集合,并返回某个已经完成了任务的结果。
-
ExecutorService#invokeAll方法,提交并返回所有结果,缺点是需要等待。
执行器完成服务ExecutorCompletionService可以按结果可获得顺序保存结果,而invokeAll可能因为第一个任务耗时太长而等待。相当于ExecutorCompletionService优化了任务执行顺序。
Fork-Join框架
适合处理计算密集型任务,可以由大到小分解子任务的任务。
使用框架完成类似的可分解子任务的递归计算时,需要提供一个扩展RecursiveTask(用于有返回)的类或者提供一个扩展RecursiveAction(用于没返回)的类,再覆盖compute方法来生成并调用子任务。
例:
class Counter extends RecursiveTask<Integer> {
. . .
protected Integer compute() {
if (to - from < THRESHOLD) {
// 实际处理,临界值设置
} else {
int mid = (from + to) / 2;
Counter first = new Counter(values, from, mid, filter);
Counter second = new Counter(values, mid, to, filter);
invokeAll(first, second); // 接收任务并阻塞直到完成
return first.join() + second.join(); //join用于生成结果
}
}
}
Fork-Join框架用了一种叫工作密取的方法平衡可用线程的工作负载。每个工作线程都有一个双端队列,一个工作线程将子任务压入队头(只有一个线程可以访问队头,因此不用加锁)。一个工作线程空闲时,会从另一个双端队列的队尾取一个任务。由于大的子任务都在队尾,所以密取很少出现。
CompletableFuture
CompletableFuture提供了“组合”的能力。可以将一个个异步任务组合起来。通过它,可以指定你希望做声明,以及希望以声明顺序执行这些工作。当然,这不会立即发生,不过重要的是代码都在一个地方。下面是它提供的一些功能。
下表的功能负责给一个CompletableFuture对象添加动作
| 方法 | 参数 | 描述 |
|---|---|---|
| thenApply | T->U | 对结果应用一个函数 |
| thenCompose | T -> CompletableFuture | 对结果调用函数并执行返回的future |
| handle | (T, Throwable) -> U | 处理结果或错误 |
| thenAccept | T -> void | 类似thenApply,不过结果为void |
| whenComplete | (T, Throwable) -> | 类似handle,结果为void |
| thenRun | Runnable | 执行Runnable |
下表的功能负责组合多个CompletableFuture对象
| 方法 | 参数 | 描述 |
|---|---|---|
| thenCombine | CompletableFuture,(T,U)->V | 执行两个动作并用给定函数组合结果 |
| thenAcceptBoth | CompletableFuture,(T,U)->void | 与thenCombine类似,不过结果为void |
| runAfterBoth | CompletableFuture<?>,Runnable | 两个都完成后执行runnable |
| applyToEither | CompletableFuture,T->V | 得到其中一个的结果时,传入给定的函数 |
| acceptEither | CompletableFuture,T->void | 与apply类似,不过结果为void |
| runAfterEither | CompletableFuture<?>,Runnable | 其中一个完成后执行runnable |
| static allOf | CompletableFuture<?>... | 所有给定的future都完成后完成,结果为void |
| static anyOf | CompletableFuture<?>... | 任意future完成后完成,结果为void |