设计Java多线程线程池时,需要考虑以下几个关键因素:
线程池大小
核心线程数量(`corePoolSize`):在没有闲置线程可用时,核心线程会一直存在。
最大线程数量(`maximumPoolSize`):当任务数量超过核心线程数量时,线程池可以创建更多的线程来处理任务。
非核心线程闲置超时时间(`keepAliveTime`):当线程池中的线程数量超过核心线程数量时,如果某个线程闲置的时间超过了`keepAliveTime`,那么它会被回收。
线程池类型
`FixedThreadPool`:适用于负载相对稳定且任务执行时间相近的场景。
`CachedThreadPool`:适用于负载波动较大且任务执行时间较短的场景。
`ScheduledThreadPool`:适用于需要定时或周期性执行任务的场景。
`SingleThreadExecutor`:适用于需要保证所有任务按顺序执行的场景。
任务队列
用于存储尚未执行的任务,当线程池的线程全部忙碌时,新添加的任务会被放入阻塞队列中等待执行。
拒绝策略
当阻塞队列已满并且线程池中的线程数量达到最大值时,需要定义如何拒绝新添加的任务。常见的拒绝策略有:
`AbortPolicy`:直接抛出`RejectedExecutionException`异常。
`CallerRunsPolicy`:由调用线程执行被拒绝的任务。
`DiscardPolicy`:直接丢弃任务,不做任何处理。
`DiscardOldestPolicy`:丢弃等待队列中等待时间最长的任务,再把当前任务放入队列中再尝试提交任务。
线程池配置建议
线程池大小通常设置为CPU核心数的1-2倍。
对于计算密集型任务,线程池大小可以设置为CPU核心数;对于I/O密集型任务,线程池大小可以设置为CPU核心数的2倍。
队列容量取决于系统资源和任务特性,通常使用无界队列(如`LinkedBlockingQueue`),但需要注意内存溢出问题。
实现线程池
可以使用`Executors`类的静态工厂方法来创建不同类型的线程池,例如`newFixedThreadPool`、`newCachedThreadPool`、`newScheduledThreadPool`和`newSingleThreadExecutor`。
创建线程池时,需要考虑任务队列的实现,通常使用`Collections.synchronizedList`将列表转换为线程安全的类。
设计线程池时,应该根据实际的应用场景和需求来选择合适的线程池类型和配置参数,以达到最佳的性能和资源利用。