为啥用线程池?
线程的创建和销毁会增加系统的开销,过于频繁的创建、销毁线程,会降低系统性能和效率。
阿里巴巴推荐用ThreadPoolExecutor创建线程池
【强制】线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。 说明:使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资 源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者 “过度切换”的问题。 【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样 的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明: Executors 返回的线程池对象的弊端如下: 1) FixedThreadPool 和 SingleThreadPool : 允许的请求队列长度为 Integer.MAX_VALUE ,可能会堆积大量的请求,从而导致 OOM 。 2) CachedThreadPool 和 ScheduledThreadPool : 允许的创建线程数量为 Integer.MAX_VALUE ,可能会创建大量的线程,从而导致 OOM 。
线程池构造函数
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
-
corePoolSize
-
创建线程,如果当前线程<corePoolSize,则新建的为核心线程,否则为非核心线程
-
核心线程一直苟活在线程池,即是啥也不需要干( 除非allowCoreThreadTimeOut设置为true,长时间不干活就被杀掉)
-
-
maximumPoolSize
-
maximumPoolSize = 核心线程数+非核心线程数
-
-
keepAliveTime
-
非核心线程闲置(不干活)超过这个时长,就会被杀掉
-
设置 allowCoreThreadTimeOut = true ,该buff也作用于核心线程
-
-
unit
-
TimeUnit的枚举类
NANOSECONDS : 1微毫秒 = 1微秒 / 1000 MILLISECONDS : 1毫秒 = 1秒 /1000 SECONDS : 秒 MINUTES : 分 HOURS : 小时 DAYS : 天
-
-
workQueue
-
当所有核心线程都在干活时,新来的任务就会添加到这个队列中等待处理
-
当等待队列满时,新建非核心线程执行任务
-
常用的workQueue类型:
SynchronousQueue : 接到任务直接交给线程处理,而不保留到队列,如果所有线程都在工作,就新建一个线程
LinkedBlockingQueue : 接到任务,如果当前线程数小于corePoolSize,则新建核心线程处理任务;如果当前线程数等于核心线程数,进入等待队列。此队列无最大值限制,只要超过corePoolSize,就被丢到这个队列
ArrayBlockingQueue : 可以限定队列长度,如果当前线程数小于corePoolSize,则新建核心线程处理任务;如果当前线程数等于核心线程数,进入等待队列;如果等待队列满,则新建非核心线程;如果线程总数到了maximumPoolSize,则发生错误
DelayQueue : 接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务
-
-
threadFactory
-
这是一个接口,代表创建线程的方式,使用的时候要实现他的 Thread newThread(Runnable r)方法
-
-
handler
-
RejectedExecutionHandler 当等待队列满,创建非核心线程,当线程总数达到maximumPoolSize,根据以下拒绝策略抛出异常
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常 ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常 ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)。
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
-
总结
要想用好线程池,要熟悉ThreadPoolExecutor这个核心构造函数,许多线程池的相关工具类都是集成于这个底层构造函数的,所以理解各个参数的含义特别重要~~~