FixedThreadPool
核心线程数和最大线程数是一样的,特点就是初始阶段需要从 0 开始增加外,之后的线程数量就是固定的。
CachedThreadPool
线程数是几乎可以无限增加的,当线程闲置时可以对线程进行回收。区别就是用于存储提交任务的队列(SynchronousQueue)容量为0,实际不存储任何任务,它只负责对任务进行中转和传递,所以效率比较高。
ScheduledThreadPool
它支持定时或周期性执行任务
ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
// 延迟10秒后执行一次任务
service.schedule(new Task(), 10, TimeUnit.SECONDS);
// 每10秒执行一次任务,执行20次
service.scheduleAtFixedRate(new Task(), 10, 20, TimeUnit.SECONDS);
// 每执行一次任务过10秒后再次执行,执行20次
service.scheduleWithFixedDelay(new Task(), 10, 20, TimeUnit.SECONDS);
SingleThreadExecutor
只会有一个线程去执行任务,如果线程在执行任务的过程中发生异常,线程池会重新创建一个线程来执行后续的任务
SingleThreadScheduledExecutor
和ScheduledThreadPool非常相似,只是把核心线程数设置成了1
ForkJoinPool
主要用法和之前的线程池是相同的,但是 ForkJoinPool 线程池有两点非常大的不同之处:
ForkJoinPool可以将一个任务分裂成多个任务最后汇总
除了公共队列线程池中的每个子线程都有自己独立的的任务队列(WorkQueue)还有一个对应的双端队列
双端队列(steal):其他空闲的子线程会去获取(work-stealing)其他繁忙线程双端队列中的任务
例子:打斐波那契数列
public static void main(String[] args) throws ExecutionException, InterruptedException {
ForkJoinPool forkJoinPool = new ForkJoinPool();
for (int i = 0; i < 10; i++) {
ForkJoinTask<Integer> task = forkJoinPool.submit(new Fibonacci(i));
System.out.println(task.get());
}
}
public class Fibonacci extends RecursiveTask<Integer> {
int n;
public Fibonacci(int n) {
this.n = n;
}
@Override
protected Integer compute() {
if (n <= 1) {
return n;
}
Fibonacci f1 = new Fibonacci(n - 1);
f1.fork();
Fibonacci f2 = new Fibonacci(n - 2);
f2.fork();
return f1.join() + f2.join();
}
}