线程池是什么?线程池(ThreadPoolExecutor)使用详解
点一点,了解更多https://www.csdn.net/
本篇文章将详细讲解什么是线程池,线程池的参数介绍,线程池的工作流程,使用Executors创建常见的线程池~~~
目录
一、线程池的概念
简单来说,可以理解为一个“现成的池子”,里面有一定数量的线程等待工作,每次使用不用再次创建、使用完了不用马上销毁,会自动回收进池子中。类似常量池等等~~
虽然创建销毁线程比创建销毁进程更轻量, 但是在频繁创建销毁线程的时候还是会比较低效,线程池就是为了解决这个问题,如果某个线程不再使用了,并不是真正把线程释放,而是放到一个“池子”中,下次如果需要用到线程就直接从池子中取,不用再次创建。
1.1线程池的目的-提高效率
池的目的就是为了提高效率,从线程池中拿线程,属于用户态操作;而从系统再去创建线程,涉及到用户态和内核态之间的切换,真正的创建是在内核态完成的。
银行中有大厅和服务柜台,大厅相当于用户态,柜台相当于内核态;每个地方都有打印机,如果来客户需要办理业务,可以在打印机上办理,也可以找工作人员办理。
此时来个老哥,说想办个银行卡,但是没带身份证复印件,有俩个办法:1.自己去大厅的复印件,自己复印一份,拿过来。2.让工作人员去柜台里面的打印机,去复印下再拿回来。
那么如果自己去复印,就立即去了,立即回来了,中间不耽误;如果工作人员去复印,他可能会做点别的,确实能给你复印,但是就不一定及时了~~
结论:用户态操作,时间是可控的;涉及到内核态操作,时间就不可控了~~
二、线程池的参数介绍
先看ThreadPoolExecutor 的构造方法
重点理解一下这几个参数含义:先情景带入一下,把线程池当作公司,一类正式员工;一类实习生;
corePoolSize:核心线程数,相当于正式员工
maxinumPoolSize:最大线程数,相当于正式员工+实习生
long keepAliveTime:实习生线程保持存活的时间
当任务比较少的时候,整体比较空闲,实习生不是立即被辞退的,表示实习生最大的存活时间
TimeUnit unit:单位,秒,分钟,毫秒
BlockingQueue
workQueue :线程池里要管理很多任务,这些任务也是通过阻塞队列来组织的,此时可以手动指定一个队列给线程池,此时就可以很方便的获取队列中的信息ThreadFactory threadFactory:工厂模式,创建线程的辅助的类
RejectedExecutionHandler handler:线程池的拒绝策略,如果任务量超出公司的负荷接下来该怎么处理
2.1线程池的拒绝策略
上述四种是标准库中提供的四种拒绝策略:
表示如果队列满了,继续添加任务, 添加操作之间抛出异常(新老都执行不了,哭)
添加的线程自己负责执行这个任务(怼回去)
丢弃最老的任务
丢弃最新的任务
以上四种策略要重点掌握,面试常考~~
三、线程池的工作流程图
四、线程池的创建
- ExecutorService 表示一个线程池实例
- Executors 是一个工厂类, 能够创建出几种不同风格的线程池
- ExecutorService 的 submit 方法能够向线程池中提交若干个任务
- Executors 本质上是 ThreadPoolExecutor 类的封装
4.1方法一
创建具有十个线程的线程池(大小固定)
public class ThreadDemo { public static void main(String[] args) { ExecutorService pool = Executors.newFixedThreadPool(10); pool.submit(new Runnable() { @Override public void run() { System.out.println("hello"); } }); }}
4.2方法二
创建一个操作无界队列且只有一个工作线程的线程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
4.3方法三
用来处理大量短时间工作任务的线程池,如果池中没有可用的线程将创建新的线程,如果线程空闲60秒将收回并移出缓存,创建线程数目动态增长的线程池
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
4.4方法四
创建一个单线程执行器,可以在给定时间后执行或定期执行。
ScheduledExecutorService singleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
4.5方法五
创建一个指定大小的线程池,可以在给定时间后执行或定期执行,是进阶版的Timer
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
4.6方法六
创建一个指定大小(不传入参数,为当前机器CPU核心数)的线程池,并行地处理任务,不保证处理顺序
Executors.newWorkStealingPool();
4.7方法七
自定义线程池,工作中使用这种方法创建线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 10, 10000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
五、模拟实现一个线程池
设置一个具有十个线程的线程池,打印0-1000个数。
其中在构造方法中调用十个线程执行,submit方法进行放入任务!!
class MyThreadPool{ private BlockingQueue queue = new LinkedBlockingQueue<>(); public void submit(Runnable runnable) throws InterruptedException { queue.put(runnable); } public MyThreadPool(int n){ for (int i = 0; i < n; i++) { Thread t = new Thread(() -> { try { while (true){ Runnable runnable = queue.take(); runnable.run(); } } catch (InterruptedException e) { e.printStackTrace(); } }); t.start(); } }}public class ThreadDemo { public static void main(String[] args) throws InterruptedException { MyThreadPool pool = new MyThreadPool(10); for (int i = 0; i < 1000; i++) { int number = i; pool.submit(new Runnable() { @Override public void run() { System.out.println("hello "+ number); } }); } Thread.sleep(3000); }}
可见,线程池中任务的执行的顺序和添加顺序不一定相同,因为这十个线程是无序调度的
来源地址:https://blog.csdn.net/asad21654864/article/details/129800272
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341