这篇文章主要讲解了“什么是线程池”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“什么是线程池”吧!
(I:代表接口,C:代表实现类)I:Executor I:ExecutorService C:AbstractExecutorService C:ThreadPoolExecutor
该类的主要构造函数如下:
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
corePoolSize:核心线程池的大小。如果核心线程池有空闲位置,新的任务进来就会被核心线程池新建一个线程执行,执行完毕后不会销毁线程,线程会进入缓存队列等待再次被运行。
maximunPoolSize:最大的线程数量。如果核心线程池和缓存队列都已经满了,新的任务进来就会创建新的线程来执行。但是数量不能超过maximunPoolSize,否侧会采取拒绝接受任务策略,我们下面会具体分析。
keepAliveTime:非核心线程能够空闲的最长时间,超过时间,线程终止。这个参数默认只有在线程数量超过核心线程池大小时才会起作用。只要线程数量不超过核心线程大小,就不会起作用。
unit:时间单位,和keepAliveTime配合使用。
workQueue: 缓存队列,用来存放等待被执行的任务,有以下取值:
1、ArrayBlockingQueue; 有界阻塞队列,详见文章:ArrayBlockingQueue详解
2、LinkedBlockingQueue; 无界阻塞队列,详见文章:LinkedBlockingQueue详解
3、SynchronousQueue; 无缓冲阻塞队列 ,详见文章:SynchronousQueue详解
threadFactory:线程工厂,用来创建线程,默认new Executors.DefaultThreadFactory();
handler: 线程拒绝策略。当创建的线程超出maximumPoolSize值,且缓冲队列已满时,对新提交任务的处理策略,有以下4种取值,我们结合代码分析
1、ThreadPoolExecutor.AbortPolicy 无视任务(也就是丢弃任务),并通过抛异常告知调用者“我拒绝接收新任务”
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { //这里直接抛出异常,可理解为:无视任务(也就是丢弃任务),并通过抛异常告知调用者“我拒绝接收新任务” throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); }
2、ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不做任何处理。
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { //这里是空实现,也就是丢弃任务,不作任何的处理 //这会导致:虽然此策略被触发,但调用者根本不知道它提交进来的任务,最终到底有没有被执行 }
3、ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,尝试执行新任务。
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { //判断线程池是否被关闭了 e.getQueue().poll();//丢弃队列最前面的任务 e.execute(r); //尝试执行新任务 } }
4、ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { //判断线程池是否被关闭了 r.run(); //调用线程直接调用run()方法,执行其代码逻辑 } }
基于ThreadPoolExecutor 的构造参数如此之多,JDK为我们提供了Executors类,通过它我们可以简单的创建出四种类型的线程池,一般场景下够用了。
1.3.1、固定大小线程池
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor( nThreads, // corePoolSize nThreads,// maximumPoolSize 0L, TimeUnit.MILLISECONDS,// keepAliveTime=0秒 new LinkedBlockingQueue<Runnable>()// 利用无界阻塞队列 ); }
参数:corePoolSize = 固定值,maximumPoolSize = 固定值,keepAliveTime = 0秒 ,workQueue = LinkedBlockingQueue 无界阻塞队列
分析:
1、corePoolSize 和 maximumPoolSize 都为 nThreads 一个固定值,说明此线程池中都是核心线程,keepAliveTime为非核心线程空闲时间,该线程池中不存在非核心线程,所以参数keepAliveTime在此处无效;
2、new LinkedBlockingQueue<Runnable>() :缓存队列用的无界阻塞队列,当核心池子里的线程都在忙的时候,新进来的任务被放到此队列中;一旦有空闲的线程了,该线程就会从队列里去拿任务执行;
3、缺点:因为用的是无界队列,所以当 nThreads 个线程一直被占用的情况下,同时又不断的有新任务进来,就有可能导致OOM问题;
1.3.2、单个线程的线程池
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, // corePoolSize,maximumPoolSize 0L, TimeUnit.MILLISECONDS,// keepAliveTime=0秒 new LinkedBlockingQueue<Runnable>())// 利用无界阻塞队列 ); }
参数:corePoolSize = 1,maximumPoolSize = 1,keepAliveTime = 0秒 ,workQueue = LinkedBlockingQueue 无界阻塞队列
分析:
1、corePoolSize 和 maximumPoolSize 都为1,此线程池只有一个核心线程,同上,参数keepAliveTime在此处无效;
2、new LinkedBlockingQueue<Runnable>() :缓存队列用的无界阻塞队列,当仅有的一个核心线程在忙的时候,新进来的任务被放到此队列中;待线程空闲了,就会从队列里去拿任务执行;
3、缺点:因为用的是无界队列,所以当核心线程一直被占用的情况下,同时又不断的有新任务进来,就有可能导致OOM问题;
4、有没有注意到,这里为什么用了一个FinalizableDelegatedExecutorService类呢?
见文章:关于newSingleThreadExecutor中的FinalizableDelegatedExecutorService源码分析
1.3.3、缓存线程池
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE,// corePoolSize,maximumPoolSize 60L, TimeUnit.SECONDS,// keepAliveTime=60秒 new SynchronousQueue<Runnable>());// 同步阻塞队列 }
参数:corePoolSize = 0,maximumPoolSize = 无限大,keepAliveTime = 60秒(重要) ,workQueue = SynchronousQueue 无缓冲阻塞队列
分析:一个可以根据需要创建线程的线程池,此线程池中所有线程都为非核心线程,且最大空闲时间为60秒,最多可以创建Integer.MAX_VALUE 个线程(2^31次方,21亿多,可以视为无限);SynchronousQueue 为无缓冲阻塞队列,也就是此队列里不会缓冲新的任务,有新任务进来时,如果无空闲线程,就会新创建一个线程;如果有空闲线程,就会使用空闲线程;所以此线程池适合执行一些执行周期短的任务。
感谢各位的阅读,以上就是“什么是线程池”的内容了,经过本文的学习后,相信大家对什么是线程池这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。