笔记来源:Java入门基础视频教程,java零基础自学就选黑马程序员Java入门教程
(资料图片仅供参考)
一、线程池概述
概念:
线程池就是一个可以复用线程的技术。
不适用线程池的问题:
如果用户每发起一个请求,后台就创建一个新线程来处理,下次新任务来了又要创建新线程,而创建新线程的开销是很大的,这样会严重影响系统的性能。
工作原理:
线程池通过提供固定的核心线程(工作线程WorkThread)和任务队列(WorkQueue)来工作,当核心线程都在忙时,新来的任务进入任务队列,等待核心线程的处理。
二、线程池实现的API、参数说明
JDK5.0起提供了代表线程池的接口,ExecutorService。
ExcutorService常用方法:
void execute(Runnable command):执行任务/命令,没有返回值,一般用来执行Runnable任务。
Future<T> submit(Callable<T> task):执行任务,返回未来任务对象获取线程结果,一般拿来执行Callable任务。
void submit():等任务执行完毕后关闭线程池。
List<Runnable> shutdownNow():立刻关闭,停止正在执行的任务,并返回队列中未执行的任务。
如何得到一个线程池对象:
方式一:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象。
ThreadPoolExecutor构造器的参数说明:
指定线程池的线程数量(核心线程):corePoolSize,不能小于0。
指定线程池可支持的最大线程数:maximumPoolSize,最大数量>=核心线程数量。
指定临时线程的最大存活时间:keepAliveTime,不能小于0。
指定存活时间的单位(秒、分、时、天):unit,时间单位。
指定任务队列:workQueue,不能为null。
指定用哪个线程工厂创建线程:threadFactory,不能为null。
指定线程忙,任务满时,新任务来了怎么办:handler,不能为null。
方式二:使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象。
Executors的底层也是基于线程池的实现类ThreadPoolExecutor创建线程池对象的。
Executors得到线程池对象的常用方法:
public static ExecutorService newCachedThreadPool():线程数量随着任务增加而增加,如果线程任务执行完毕且空闲了一段时间则会被回收掉。
public static ExecutorService newFixedThreadPool(int nThreads):创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程替代它。
public static ExecutorService newStringThreadExecutor():创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize):创建一个线程池,可以实现在给定的延迟后运行任务,或者定期执行任务。
Executors使用可能存在的陷阱:
大型并发系统环境中使用Executors如果不注意可能会出现系统风险。
可能会出现OOM错误(Java.lang.OutOfMemoryError)。
三、线程池处理Runnable任务
ThreadPoolExecutor创建线程池对象:
新任务拒绝策略:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常,是默认的策略。
ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常,这是不推荐的做法。
ThreadPoolExecutor.DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中。
ThreadPoolExecutor.CallerRunsPolicy:由主线程负责调用任务的run()方法从而绕过线程池直接执行。
给一个任务给线程池处理:
四、线程池处理Callable任务
五、线程池常见面试题
临时线程什么时候创建?
新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程。
什么时候会开始拒绝任务?
核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始任务拒绝。