欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 新车 > 谈一谈线程池以及ThreadPoolExecutor

谈一谈线程池以及ThreadPoolExecutor

2024/10/25 3:24:02 来源:https://blog.csdn.net/qq_21880261/article/details/143215875  浏览:    关键词:谈一谈线程池以及ThreadPoolExecutor

文章目录

  • 线程池
  • newSingleThreadExecutor
  • newFixedThreadPool
  • newCachedThreadPool
  • newScheduledThreadPool
  • 自定义线程池

线程池

线程池就是容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象、销毁线程的操作,避免系统资源的浪费。

线程池的优势?线程复用:         通过线程复用降低线程的创建和销毁造成的消耗提升响应速度:      当任务到达时,任务可以不需要等到线程创建就可以执行。提高线程的可管理性: 控制线程的并发数量,统一分配、管理线程常用的线程池
1Executors.newSingleThreadExecutor(int)   任务按序执行    LinkedBlockingQueue
2Executors.newFixedThreadPool(int)        执行长期的任务  LinkedBlockingQueue
3Executors.newCachedThreadPool(int)       执行短期异步的小程序	SynchronousQueue
4Executors.newScheduledThreadPool(int)    延迟重复执行线程

在这里插入图片描述

newSingleThreadExecutor

定义:单线程化线程池(只有一个线程),单线程化的线程池中的任务是按照提交的次序顺序执行的,唯一线程的存活时间是无限的,当池中的唯一线程正繁忙时,新提交的任务实例会进入内部的阻塞队列中,并且其阻塞队列是无界的

适用场景:任务按照提交次序,一个任务一个任务地逐个执行的场景

案例:

public class MyRunnable implements Runnable {private String taskName;public MyRunnable(String taskName) {this.taskName = taskName;}public void run() {System.out.println("task:" + taskName + " is doing...");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("task:" + taskName + " end...");}
}public class Demo01_SingleThreadExecutor {public static void main(String[] args) {//1、获取线程池对象ExecutorService es = Executors.newSingleThreadExecutor();//2、提交任务for (int i = 1; i < 11; i++) {es.submit(new MyRunnable("任务" + i));}//3、关闭线程//es.shutdown();//关闭线程池,不接受新的任务,原来的任务继续执行//es.submit(new MyRunnable(88));//报错,不接受新任务//        List<Runnable> al = es.shutdownNow();//立刻关闭线程池,若线程池还有缓存的任务,立即取消,并返回
//        System.out.println(al);// es.submit(new MyRunnable(99));//报错,不接受新任务}
}

newFixedThreadPool

定义:固定数量的线程池,如果线程数没有达到“固定数量”,每次提交一个任务线程池内就创建一个新线程,直到线程达到线程池固定的数量,线程池的大小一旦达到“固定数量”就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程

适用场景:

  • 需要任务长期执行的场景
  • CPU密集型任务

缺点:

  • 内部使用无界队列来存放排队任务,当大量任务超过线程池最大容量需要处理时,队列无限增大,使服务器资源迅速耗尽

案例:

public class demo26Thread06 {public static void main(String[] args) {//1、获取线程池对象ExecutorService es = Executors.newFixedThreadPool(3);//2、提交任务for (int i = 1; i < 11; i++) {es.submit(new MyRunnable("任务" + i));}}
}

在这里插入图片描述

newCachedThreadPool

特点:

​ 1、可缓存线程池在接收新的异步任务target执行目标实例时,如果池内所有线程繁忙,此线程池就会添加新线程来处理任务

​ 2、线程池不会对线程池大小进行限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小

​ 3、如果部分线程空闲,也就是存量线程的数量超过了处理任务数量,就会回收空闲(60秒不执行任务)线程

适用场景:

​ 需要快速处理突发性强、耗时较短的任务场景,如Netty的NIO处理场景、REST API接口的瞬时削峰场景

缺点:

​ 线程池没有最大线程数量限制,如果大量的异步任务执行目标实例同时提交,可能会因创建线程过多而导致资源耗尽

案例:

public class Demo03_CachedThreadPool {public static void main(String[] args) {//1、获取线程池对象ExecutorService threadPool = Executors.newCachedThreadPool();//3、提交任务try {for (int i = 1; i < 11; i++) {threadPool.submit(new MyRunnable("任务" + i));}} catch (Exception e) {e.printStackTrace();} finally {threadPool.shutdown();//关闭线程池}}
}

在这里插入图片描述

newScheduledThreadPool

  • 延时性
  • 周期性

案例:

public class demo28Thread08 {public static void main(String[] args) {test01();// test02();间隔时间不同
//        test03();}/*** 1、延迟2s执行* es.schedule(new MyRunnable("任务"+i),2, TimeUnit.SECONDS);*/private static void test01() {//1、获得延迟线程池对象ScheduledExecutorService es = Executors.newScheduledThreadPool(3);//2、编写任务类//3、提交多个任务for (int i = 1; i < 11; i++) {es.schedule(new MyRunnable("任务" + i), 2, TimeUnit.SECONDS);}}/*** 2、间隔时间不同* es.scheduleAtFixedRate(new MyRunnable("任务"+i),1,2,TimeUnit.SECONDS)*/private static void test02() {//1、获得延迟线程池对象ScheduledExecutorService es = Executors.newScheduledThreadPool(3, new ThreadFactory() {int n = 1;public Thread newThread(Runnable r) {return new Thread(r, "自定义线程池名称" + n++);}});//2、编写任务类//3、提交多个任务for (int i = 1; i < 11; i++) {es.scheduleAtFixedRate(new MyRunnable("任务" + i), 1, 2, TimeUnit.SECONDS);}System.out.println("执行完成");}/*** es.scheduleWithFixedDelay(new MyRunnable("任务"+i),1,2,TimeUnit.SECONDS)*/private static void test03() {//1、获得延迟线程池对象ScheduledExecutorService es = Executors.newScheduledThreadPool(3, new ThreadFactory() {int n = 1;public Thread newThread(Runnable r) {return new Thread(r, "自定义线程池名称" + n++);}});//2、编写任务类//3、提交多个任务for (int i = 1; i < 11; i++) {es.scheduleWithFixedDelay(new MyRunnable("任务" + i), 1, 2, TimeUnit.SECONDS);}System.out.println("执行完成");}
}

自定义线程池

自定义线程池ThreadPoolExecutor【七大参数】
在这里插入图片描述

1:核心线程数(corePoolSize):		线程池中常驻核心线程数
2:最大线程数(maximumPoolSize):	线程池能够容纳同时执行的最大线程数
3:keepAliveTime: 			    非核心线程最大存活时间,若当前线程池数量超过核心线程数corePoolSize,当空闲时间达到keepAliveTime,多余非核心线程会被销毁直到只剩下corePoolSize个线程。
4:unit: 						keepAliveTime的单位
5:任务队列(workQueue):   		 被提交但尚未执行的任务,存放在阻塞队列中
6:线程工厂(threadFactory): 		 用于创建线程,一般默认即可。
7:拒绝策略(handler):			 表示当等待队列满了并且工作线程大于等于线程池的最大线程数常见拒绝策略:AbortPolicy(默认):		   直接抛出异常RejectedExecutionException,阻止系统正常运行CallerRunsPolicy: 	  		调用者优先策略,该策略不会抛弃任务,也不会抛出异常,而是将某些任务回退DiscardOldestPolicy:		抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务DiscardPolicy:				直接丢弃任务,不做任何处理也不抛出异常。如果允许任务丢失,可以使用

底层原理
在这里插入图片描述

1、在创建了线程池之后,等待提交过来的任务请求
2、当调用execute()方法后添加一个请求任务2.1 如果正在运行的线程数量小于corePoolSize,则立即执行该任务2.2 如果正在运行的线程数量大于等于corePoolSize,则将该任务放进队列 workQueue2.3 如果任务队列满了,并且正在运行的线程数量小于maximumPoolSize,那么线程池创建非核心线程执行任务2.4 如果任务队列满了,并且正在运行的线程数量大于等于maximumPoolSize,那么线程池启动拒绝策略执行。
3、当一个线程完成任务时,它会从队列取下一个任务执行
4、当一个线程无事可做超过一定的时间keepAliveTime,线程池会判断4.1 如果运行的线程数大于corePoolSize,那么会停掉该非核心线程4.2 最后线程池的线程数目收缩到corePoolSize的大小

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com