4.1. 为什么要用线程池?
- 降低资源消耗。
- 提高响应速度。
-
4.2. 实现 Runnable 接口和 Callable 接口的区别
Runnable自 Java 1.0 Callable仅在 Java 1.5 中引入
Runnable 接口 不会返回结果或抛出检查异常,但是 Callable 接口 可以。4.3. 执行 execute()方法和 submit()方法的区别是什么呢?
execute()方法用于提交不需要返回值的任务
submit()方法用于提交需要返回值的任务。线程池会返回一个 Future 类型的对象
4.4. 如何创建线程池
Executors 和ThreadPoolExecutor
方式一:通过构造方法实现
方式二:通过 Executor 框架的工具类 Executors 来实现FixedThreadPool : 该方法返回一个固定线程数量的线程池。
- SingleThreadExecutor: 方法返回一个只有一个线程的线程池。
CachedThreadPool: 该方法返回一个可根据实际情况调整线程数量的线程池。
4.5 ThreadPoolExecutor 类分析
构造方法参数:
ThreadPoolExecutor 3 个最重要的参数:corePoolSize : 核心线程数定义了最小可以同时运行的线程数量。
- maximumPoolSize : 当队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。
- workQueue: 当新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中。
ThreadPoolExecutor其他常见参数:
- keepAliveTime:当线程池中的线程数量大于 corePoolSize 的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了 keepAliveTime才会被回收销毁;
- unit : keepAliveTime 参数的时间单位。
- threadFactory :executor 创建新线程的时候会用到。
- handler :饱和策略。关于饱和策略下面单独介绍一下。
4.5.2 ThreadPoolExecutor 饱和策略
ThreadPoolExecutor 饱和策略定义:
如果当前同时运行的线程数量达到最大线程数量并且队列也已经被放满了任务时,ThreadPoolTaskExecutor 定义一些策略:
- ThreadPoolExecutor.AbortPolicy: 抛出 RejectedExecutionException来拒绝新任务的处理。
- ThreadPoolExecutor.CallerRunsPolicy: 调用执行自己的线程运行任务,也就是直接在调用execute方法的线程中运行(run)被拒绝的任务,如果执行程序已关闭,则会丢弃该任务。因此这种策略会降低对于新任务提交速度,影响程序的整体性能。如果您的应用程序可以承受此延迟并且你要求任何一个任务请求都要被执行的话,你可以选择这个策略。
- ThreadPoolExecutor.DiscardPolicy: 不处理新任务,直接丢弃掉。
- ThreadPoolExecutor.DiscardOldestPolicy: 此策略将丢弃最早的未处理的任务请求。
4.7 线程池原理分析