线程池的作用
当系统频繁的创建和销毁线程的时候,就会大大的降低系统的效率。线程池就是为了解决这个问题,使得线程在执行完一个任务的时候,不被销毁,而是继续执行下一个任务。可以有效的提高系统的效率。
线程池初步了解
线程池主要使用ExecutorService线程池接口。
如:ExecutorService pool = Executor.常见线程。
常见线程包括:
1. newCachedThreadExecutor 适用于执行短期异步的小程序或者负载较轻的服务器。
newCachedThreadExecutor是可缓存线程池,当线程池大小超过了执行任务所需的线程大小时,就会回收部分空闲(60秒无执行)的线程,当任务来时,又可智能的添加线程来执行。
2. newFixedThreadPool 适用于长期任务,性能较好
newFixedThreadPool 线程池的大小固定,每提交一个任务,就是一个线程,直至达到线程池的最大数量。然后后边进入的进入等待队列,直到前边的任务执行完毕才可以执行。
3. newSingleThreadPool 适用于一个任务一个任务执行的场景
newSingleThreadPool 单线程线程池,即线程池中只有一个线程,单线程串行执行任务。
4. newScheduleThreadPool 适用于周期性执行任务
newScheduleThreadPool 大小无限制的线程池,适用于定时和周期性的执行任务。
线程池的核心类ThreadPoolExecutor
ThreadPoolExecutor类的构造方法,
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandle handle)
TheadPoolExecutor类共有四个构造方法,最后两个参数可以没有,可以只有一个,可以两个都有。
几个参数的意义:
corePoolSize:核心池的大小。默认情况下,在创建线程池之后,线程池中线程个数为0,当任务来时,创建一个线程,当任务数达到corePoolSize之后,就会把后边来到的任务放入到缓存队列当中。这个corePoolSize还可以结合上一篇的生产者消费者模式,进行理解,它就是消费者线程的大小。
maximumPoolSize 最大线程数,表示线程池中最大可以创建的线程数。
keepAliveTime 线程活跃时间,表示线程在没有任务执行时,最长的存在多久不被结束。默认情况下,只有当线程池中线程超过corePoolSize时,才会起作用。
TimeUnit 线程池参数中keepAliveTime的单位,有7中静态属性,TimeUnit.DAYS,TimeUnit.HOURS,TimeUnit.MINUTES,SECONDS,MILLSECONDS,MICROSECONDS,NANOSECONDS。
BlockingQueue 阻塞队列,用于存储等待执行的任务。常见的选择有三种:ArrayBlockingQueue,LinkedBlockingQueue和SynchronousQueue。
ThreadFactory 线程工厂,用于创建线程。
RejectedExecutionExecute 当拒绝执行任务时的策略,有以下四种方式:ThreadPoolExecutor.AbortPolicy,丢弃任务并抛出异常,DiscardPolicy:丢弃任务,但不抛出异常。DiscardOldestPolicy:丢弃队列最前边的任务,并重新执行。CallerRunsPolicy:由调用线程处理任务。
线程池任务执行流程
-
当线程池中线程小于coreThreadPool时,每提交一个任务,线程池就创建一个新线程。
-
当线程达到coreThreadPool时,新提交的任务会被放到缓存队列中,等待系统调度。
-
当workQueue已满,且maximumThreadPool>coreThreadPool时,新提交任务,系统会创建新线程去执行任务。
-
当提交任务数,超过maximum时,新提交任务会交由RejectedExecutionHandle处理
-
当线程池中线程超过coreThreadPool,且空闲时间达到keepAliveTime时,系统会释放空闲线程。
-
当设置allowCoreThreadPoolTimeOut(ture)时,线程池中coreThreadPool达到keepAliveTime也将关闭。
实例演练
线程池大小设置
如果是CPU密集型的,尽量多使用CPU,可设置线程池大小为CPU核数 1,
如果是IO密集型的,可设置大小为2*CPU核数