什么是线程池?
线程池是一种多线程处理方式,处理任务的过程中将任务交给线程池来管理。
为什么要使用线程池?
创建线程和销毁线程的花销是比较大的,这些时间有可能比处理业务的时间还要长。如果每执行一条任务都要创建一个线程的话,服务器的资源很快就会耗尽,使用线程池可以减少线程创建和销毁的次数,每个工作线程都可以被重复利用,可以执行多个任务。
线程池有什么作用?
1.提高效率,创建好一定数量的线程放入线程池里,当有任务需要执行时就从线程池中拿出一个工作线程去执行任务,比需要时才创建线程的效率要快。
2.方便管理,可以修改线程池参数对线程池中的线程进行管理,比如说启动时有该程序创建100个线程,每当有请求的时候,就分配一个线程去工作,如果刚好并发有101个请求,那多出的这一个请求可以排队等候,避免因无休止的创建线程导致系统崩溃。
线程池的重要参数
1.corePoolSize:线程池中的核心线程的数量,该线程在没有使用的情况下也不会被回收。
2.maximumPoolSize:线程池中可以容纳最多的线程数量
3.keepAliveTime:线程中(除核心线程之外的线程)的最长保留时间,如果非核心线程在最长保留时间之内还没有获取到任务的话,会被回收。
4.util:计算时间的单位,时分秒。
5.workQueue:等待队列,任务可以存储在任务队列中等待被执行(执行原则:先进先出)。
6.threadFactory:创建线程的线程工厂
7.handler:一种拒绝策略
拒绝策略
当请求任务不断的过来,而系统此时又处理不过来的时候,我们需要采取的策略是拒绝服务。
RejectedExecutionHandler接口提供了拒绝任务处理的自定义方法的机会。在ThreadPoolExecutor中已经包含四种处理策略。
1.AbortPolicy策略:该策略会直接抛出异常,阻止系统正常工作。
2.CallerRunsPolicy 策略:只要线程池未关闭,该策略直接在调用者线程中,运行当前的被丢弃的任务。
3.DiscardOleddestPolicy策略: 该策略将丢弃最老的一个请求,也就是即将被执行的任务,并尝试再次提交当前任务。
4.DiscardPolicy策略:该策略默默的丢弃无法处理的任务,不予任何处理。
除了JDK默认提供的四种拒绝策略,我们可以根据自己的业务需求去自定义拒绝策略,自定义的方式很简单,直接实现RejectedExecutionHandler接口即可。
execute和submit的区别?
(1)可以接受的任务类型
execute只能接受Runnable类型的任务
submit不管是Runnable还是Callable类型的任务都可以接受
(2)返回值
execute没有返回值
submit有返回值,所以需要返回值的时候必须使用submit
(3)异常
1.execute中抛出异常
execute中的是Runnable接口的实现,所以只能使用try、catch来捕获CheckedException,通过实现UncaughtExceptionHande接口处理UncheckedException
即和普通线程的处理方式完全一致
2.submit中抛出异常
不管提交的是Runnable还是Callable类型的任务,如果不对返回值Future调用get()方法,都会吃掉异常
五种线程池的使用场景
1.newSingleThreadExecutor:一个单线程的线程池,可以用于需要保证顺序执行的场景,并且只有一个线程在执行。
2.newFixedThreadPool:一个固定大小的线程池,可以用于已知并发压力的情况下,对线程数做限制。
3.newCachedThreadPool:一个可以无限扩大的线程池,比较适合处理执行时间比较小的任务。
4.newScheduledThreadPool:可以延时启动,定时启动的线程池,适用于需要多个后台线程执行周期任务的场景。
5.newWorkStealingPool:一个拥有多个任务队列的线程池,可以减少连接数,创建当前可用cpu数量的线程来并行执行。
线程池的关闭
shutdownNow:对正在执行的任务全部发出interrupt(),停止执行,对还未开始的任务全部取消,并且返回还没开始的任务列表
shutdown:当我们调用shutdown后,线程池将不再接受新的任务,但不回去强制终止正在执行或已经提交的任务。
线程池都有哪几种工作队列
1、ArrayBlockingQueue
是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
2、LinkedBlockingQueue
一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列
3、SynchronousQueue
一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
4、PriorityBlockingQueue
一个具有优先级的无限阻塞队列。