一、线程池策略选择
线程池在多线程编程中起到了至关重要的作用,可以有效地管理线程,提高系统的性能,降低线程创建和销毁带来的开销。在使用线程池时,我们需要注意选择适合当前系统的线程池策略。
Java提供的线程池主要有四种策略:
- FixedThreadPool:一个固定大小的线程池,管理一组最多的线程,如果有多余的任务,则将其放入队列中等待运行。
- CachedThreadPool:一个可变大小的线程池,根据需要创建新线程,当有线程空闲时会重复利用已创建的线程。
- SingleThreadExecutor:只有一个线程的线程池,顺序执行每一个任务。
- ScheduledThreadPool:类似于FixedThreadPool,但可以定时执行任务或延迟执行任务。
二、线程池什么时候触发拒绝策略
当线程池中线程的数量达到最大值并且任务队列已经满时,新提交的任务将会触发线程池拒绝策略。
三、线程池策略模式
线程池使用策略模式来定义不同的拒绝策略。Java提供了四种默认的拒绝策略:AbortPolicy、CallerRunsPolicy、DiscardOldestPolicy和DiscardPolicy。
四、线程池拒绝策略参数
线程池中有两个参数与拒绝策略相关:corePoolSize和maximumPoolSize。corePoolSize 表示线程池中核心线程的数量,maximumPoolSize 表示线程池中最大线程的数量。如果线程池中线程数量未达到 corePoolSize,则会创建一个新的线程执行任务;如果达到 corePoolSize 并且任务队列已满,则会按照线程池策略拒绝任务。
五、线程池策略CallerRunsPolicy
CallerRunsPolicy 是 JDK 内置的拒绝策略之一,当线程池无法执行任务时,将任务直接交给调用 execute 方法的线程执行。
public class CallerRunsPolicy implements RejectedExecutionHandler { public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } } }
六、线程池抛弃策略
DiscardPolicy 是 JDK 内置的拒绝策略之一,当线程池无法执行任务时,直接丢弃该任务。
public class DiscardPolicy implements RejectedExecutionHandler { public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { // do nothing } }
七、线程池callrun策略
CallerRunsPolicy 是 JDK 内置的拒绝策略之一,当线程池无法执行任务时,将任务直接交给调用 execute 方法的线程执行。
public class CallerRunsPolicy implements RejectedExecutionHandler { public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } } }
八、线程池应该采取哪种拒绝策略
选择线程池拒绝策略需要根据实际场景,不同的拒绝策略有不同的应用场景。
- AbortPolicy:默认的拒绝策略,在任务无法执行时直接抛出异常。
- CallerRunsPolicy:当线程池中已有正在执行的线程时,调用 execute 方法的线程将直接执行待执行的任务。
- DiscardPolicy:当任务无法执行时直接丢弃该任务。
- DiscardOldestPolicy:当任务无法执行时丢弃一些队列中最老的任务,并将新任务加入队列。
九、线程池拒绝策略
用户也可以自定义拒绝策略,只需实现 RejectedExecutionHandler 接口并实现 rejectedExecution 方法即可。例如,我们可以将无法执行的任务写入日志等。
public class MyRejectedExecutionHandler implements RejectedExecutionHandler { public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { // my custom rejection policy } }
十、线程池饱和策略选取
线程池的饱和策略选取需要根据实际情况进行选择。如果希望能够快速响应并抛出异常,则可以选择 AbortPolicy 等策略;如果希望利用已有线程执行任务,则可以选择 CallerRunsPolicy 等策略;如果希望最大限度地利用系统资源,则可以选择 DiscardOldestPolicy 或自定义拒绝策略。