在Java里,线程池的运用场景很多,几乎所有需要异步或者并发执行任务的程序都可以使用线程池。
目录
线程池的好处
线程池的工作流程
线程池的组成元素
向线程池提交任务
关闭线程池
Java自带的四种线程池
降低资源消耗。通过重复利用已创建的线程降低了创建线程和销毁线程的资源消耗
提高了响应速度。当有任务时,任务可以不用等线程的创建就可以执行
当你向线程池提交了一个任务后,线程池判断核心线程池里的线程是否都在执行任务,如果不是,则创建一个新的线程去执行这个任务。如果核心线程都在执行任务再判断工作队列是否已满,如果没满,就把任务存储在工作队列里。如果工作队列已满,就判断线程池的线程是否已满,如果满了则执行饱和拒绝策略,如果没满则创建新的线程去完成任务。
ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime, TimeUnit unit,BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
当你需要创建一个线程池的时候需要上面的几个参数
corePoolSize:核心线程池的大小也可以理解为线程池的基本大小,当你提交一个任务给线程池的时候,线程池就会创建一个线程来执行任务,即使其他空闲的核心线程能够执行任务也会去创建新的核心线程去执行,等到完成预热即需要执行的任务数大于线程池基本大小的时候就不会再创建了。
maximumPoolSize:线程池所允许创建的最大线程数,如果工作队列满了,并且创建的线程数小于最大线程数,线程池就会再创建新的线程执行任务,如果工作队列是无界(LinkedBlockingQueue),那么这个参数就没有什么实际效果了。
keepAliveTime:线程池的工作线程空闲后,保持存活的时间,当任务比较多且每个任务的执行时间比较短的时候,可以将时间调大,以此提高线程的利用率。
TimeUnit :线程存活时间的单位。
workQueue:工作队列,用来保存等待执行的任务的阻塞队列。
ThreadFactory :设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置名字
RejectedExecutionHandler:饱和拒绝策略,当队列与线程池都满了,就说明线程池处于一种饱和状态,就需要采用一种策略来处理提交的新任务。一般默认是AbortPolicy。
向线程池提交任务有两个方法,execute()与submit();
execute()方法用于提交无返回值的任务,所以你无法去判断这个任务是否被线程池执行成功
submit()方法用于提交有返回值的任务,线程池会返回一个future类型的对象。可以用这个对象去判断任务是否执行成功。可以通过future的get()方法来获取返回的值。
关闭线程池有两种方式,shutdown()与shutdownNow()去关闭线程池。它们都是通过遍历线程池中的工作线程,然后调用线程的interrupt()方法来中断线程,所以无法响应中断的线程将会无法终止。shutdownNow是先将线程池的状态设置为STOP,然后再去尝试停止每一个正在执行或者暂停的线程,并且返回等待任务的列表。而shutdown是将线程池的状态设置为SHUTDOWN状态,然后中断所有没有正在执行的的线程。
Java里推荐里4种线程池,分别是:FixedThreadPool、SingleThreadExecutor、CachedThreadPool、ScheduledThreadPoolExecutor。
FixedThreadPool被称为可重用固定线程数的线程池,它的corePoolSize与maximumPoolSize均被设置为创建线程池时指定的参数nThreads.当线程池的线程数大于corePoolSize时,keepAliveTime被设置为0,这意味着有多余的空闲线程将会被禁止。
执行过程:如果当前的运行线程数 当线程池中的线程数达到corePoolSize时,新的任务就会在无界队列中等待,因此线程池中的线程数不会超过corePoolSize。因为,此处的工作队列是无界队列,所以maximumPoolSize与keepAliveTime将会被无效化,而且运行中的FixedThreadPool在不调用shutdown()与shutdownNow()时,将不会拒绝任务。 执行过程:如果当前运行的线程的数量 执行过程:首先执行SynchronousQueue.offer(Runnable task),如果当前的maximumPool中有空闲的线程正在执行SynchronousQueue.poll方法,那么主线程执行的offer操作与空闲线程的poll操作配对成功,主线程把任务交给空闲线程去执行,如果maximumPool为空,或者当前没有空闲线程的时候,CachedThreadPool会创建一个新的线程执行任务,当这个新线程创建完毕后,会执行SynchronousQueue.poll方法,这个poll操作会让空闲线程去等待主线程的offer操作,如果60s之内,主线程给了offer操作,就会配对成功,如果没给的话,这个空闲线程会被终止。 执行过程:从DelayQueue中获取已经到期的ScheduledFutureTask,再执行这个任务,执行完毕后将这个任务的time改为下一次要执行的时间,再放回DelayQueuepublic static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue