FixedThreadPool

核心线程数和最大线程数是一样的,特点就是初始阶段需要从 0 开始增加外,之后的线程数量就是固定的。

CachedThreadPool

线程数是几乎可以无限增加的,当线程闲置时可以对线程进行回收。区别就是用于存储提交任务的队列(SynchronousQueue)容量为0,实际不存储任何任务,它只负责对任务进行中转和传递,所以效率比较高。

ScheduledThreadPool

它支持定时或周期性执行任务

  1. ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
  2. // 延迟10秒后执行一次任务
  3. service.schedule(new Task(), 10, TimeUnit.SECONDS);
  4. // 每10秒执行一次任务,执行20次
  5. service.scheduleAtFixedRate(new Task(), 10, 20, TimeUnit.SECONDS);
  6. // 每执行一次任务过10秒后再次执行,执行20次
  7. service.scheduleWithFixedDelay(new Task(), 10, 20, TimeUnit.SECONDS);

SingleThreadExecutor

只会有一个线程去执行任务,如果线程在执行任务的过程中发生异常,线程池会重新创建一个线程来执行后续的任务

SingleThreadScheduledExecutor

和ScheduledThreadPool非常相似,只是把核心线程数设置成了1

ForkJoinPool

主要用法和之前的线程池是相同的,但是 ForkJoinPool 线程池有两点非常大的不同之处:

  1. ForkJoinPool可以将一个任务分裂成多个任务最后汇总

  2. 除了公共队列线程池中的每个子线程都有自己独立的的任务队列(WorkQueue)还有一个对应的双端队列

双端队列(steal):其他空闲的子线程会去获取(work-stealing)其他繁忙线程双端队列中的任务

例子:打斐波那契数列

  1. public static void main(String[] args) throws ExecutionException, InterruptedException {
  2. ForkJoinPool forkJoinPool = new ForkJoinPool();
  3. for (int i = 0; i < 10; i++) {
  4. ForkJoinTask<Integer> task = forkJoinPool.submit(new Fibonacci(i));
  5. System.out.println(task.get());
  6. }
  7. }
  8. public class Fibonacci extends RecursiveTask<Integer> {
  9. int n;
  10. public Fibonacci(int n) {
  11. this.n = n;
  12. }
  13. @Override
  14. protected Integer compute() {
  15. if (n <= 1) {
  16. return n;
  17. }
  18. Fibonacci f1 = new Fibonacci(n - 1);
  19. f1.fork();
  20. Fibonacci f2 = new Fibonacci(n - 2);
  21. f2.fork();
  22. return f1.join() + f2.join();
  23. }
  24. }