背景:

线程是一个开发经常使用的东西,但是实际工作中很少有新建一个线程去执行任务,线程的创建和销毁都会耗费资源,我们一般都会用线程池来完成线程的创建和销毁。

  • 多说一句

JDK自带的线程池不建议大家去使用,每个都存在资源的浪费,甚至会引发OOM问题,大家都是开发,这些东西还是自己根据实际业务去创建自定义的好。

正文

  • 自定义一个线程池首先我们需要知道它怎么去构建,怎么传参,参数都是什么含义,参数传多少合适,接下来一一解开疑惑。
  • 我们首先看一下线程池的构造函数,分析一下里面的参数:

  1. CorePoolSize(核心线程数):
    就是我们经常去处理的任务的线程数量,线程池如果没有任务处理时,它们是在空闲状态,不会被销毁,有任务时,它们会直接去处理任务,如果忙不过来就会把任务添加到阻塞队列。

  2. MaximumPoolSize(最大线程数):
    上面说到核心线程来不及去处理任务,线程会放到队列中等待处理。当队列满了,没有办法继续缓存任务时,这个时候线程池会创建一个新线程去处理任务,注意:这里不是处理来的新任务,而是从队列头部拉一个出来,新任务放进去队列里面等待处理,大家都是有顺序的。
    当然这时候队列还是满的,如果任务过来还是会触发这个机制,去建新线程,这个参数就是控制可以创建的最大线程树,如果线程数量超过时,就会触发拒绝策略,下面会将。

  3. keepAliveTime(最大存活时间):
    刚才说了,如果核心线程数都忙着呢,队列也满了,我们就会创建新线程,可是如果线程都执行完任务总不能都去空闲不销毁吧。这时候肯定有一种机制去管理它们,如果空闲线程数大于核心线程数,它们多的线程最多活的时间根据这个参数来设置,到时间了,就会被销毁。

  4. Unit(单位):
    最大存活时间的单位。

  5. workQueue(阻塞队列):
    队列的作用你一定还记得,核心线程忙的时候,任务会放到队列中,JDK提供了4个队列供我们选择

    ArrayBlockingQueue: 基于数组的有边界的队列,按照先进先出排列,跟我们排队一个意思,不能插队。我们创建这个队列的时候,传一个参数就可以了,参数表示队列的容量大小。

    LinkedBlockingQuene: 基于链表的阻塞队列,也是采用先进先出,创建时如果构造函数不传队列容量大小时,默认大小为Integer.Max,也可以指定容量大小。


    SynchronousQueue: 不缓存任务的阻塞队列,任务来了以后不会缓存到队列中,直接创建一个新线程去处理任务。

    PriorityBlockingQueue: 是一个支持优先级的无界阻塞队列,直到系统资源耗尽。默认情况下元素采用自然顺序升序排列。也可以自定义类实现compareTo()方法来指定元素排序规则,或者初始化PriorityBlockingQueue时,指定构造参数Comparator来对元素进行排序。

  6. ThreadFactory(线程工厂):
    通过ThreadFactory的newThread方法,可以对创建的线程做一些操控,ThreadFactory是一个接口,我们需要实现它的newThread的方法,这时候我们就可以设置一些线程的参数,这个参数可不填,有默认的。

  7. handler :拒绝策略:
    当队列满了时且线程数达到最大线程数时,这时候任务再来时,就会触发拒绝策略来应对接下来的任务,这时候肯定是资源不够用了,我们需要根据实际场景去选择正确的策略。JDK提供了4钟拒绝策略,我们来看一下每一个策略。
    AbortPolicy: 丢弃任务并抛出RejectedExecutionException异常。这是线程池默认的拒绝策略,在任务不能再提交的时候,抛出异常,及时反馈程序运行状态。如果是比较关键的业务,推荐使用此拒绝策略,这样子在系统不能承载更大的并发量的时候,能够及时的通过异常发现。
    DiscardPolicy: 丢弃任务,但是不抛出异常。如果线程队列已满,则后续提交的任务都会被丢弃,且是静默丢弃。
    DiscardOldestPolicy: 丢弃队列最前面的任务,新任务加到队列里面,如果有新任务过来,继续这个策略。
    CallerRunsPolicy: 如果队列满了,这个任务由调用线程去执行。

实战


public static void main(String[] args) {//阻塞队列ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(200);//新建一个自定义线程池ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 50, 30, TimeUnit.SECONDS, arrayBlockingQueue);//循环输出数字for(int i =0;i<200;i++){int num = i;//submit执行方法,也可以用execute,submit具有返回值threadPoolExecutor.submit(new Runnable() {@Overridepublic void run() {try {//让子弹飞一会儿Thread.sleep(1000);//输出线程名System.out.println(num +Thread.currentThread().getName());} catch (InterruptedException e) {e.printStackTrace();}}});}//线程池使用完一定要关闭threadPoolExecutor.shutdown();}
  • 输出结果
1pool-1-thread-2
2pool-1-thread-3
3pool-1-thread-4
0pool-1-thread-1
4pool-1-thread-5
5pool-1-thread-2
7pool-1-thread-4

注意点

  • 核心线程数多少合适?
    如果是计算性任务,不涉及I/O操作,使用CPU资源比较多,这时候核心线程数和CPU核数相同,
    如果是I/O比较多,比如批量下载文件,读写数据库、redis缓存,这些I/O操作用线程池就可以优化空间很大,我们把核心线程数设置为核数的double(双倍)。

  • 线程池启动方法:
    示例中使用的submit方法,submit方法可以接收Runnable和Callable,Callable可以有返回值,让我们可以知道线程池的执行情况。也可以用execute执行方法,可以启动线程池但是没有返回值。

  • 线程池关闭方法:
    线程池使用完,一定要关闭,这里有两个方法,shutdown()和shutdownNow(),前者是需要等待线程池执行完所有任务在关闭,后者正在执行的任务停止,没有执行的任务返回。

一文搞懂Java自定义线程池参数相关推荐

  1. 一文弄懂Java中线程池原理

    在工作中,我们经常使用线程池,但是你真的了解线程池的原理吗?同时,线程池工作原理和底层实现原理也是面试经常问的考题,所以,今天我们一起聊聊线程池的原理吧. 为什么要用线程池 使用线程池主要有以下三个原 ...

  2. 从原理上搞懂如何设置线程池参数大小?

    我们在使用线程池的时候,会有两个疑问点: 线程池的线程数量设置过多会导致线程竞争激烈 如果线程数量设置过少的话,还会导致系统无法充分利用计算机资源 那么如何设置才不会影响系统性能呢? 其实线程池的设置 ...

  3. 一文搞懂 Java 线程中断

    转载自   一文搞懂 Java 线程中断 在之前的一文<如何"优雅"地终止一个线程>中详细说明了 stop 终止线程的坏处及如何优雅地终止线程,那么还有别的可以终止线程 ...

  4. Java 自定义线程池

    Java 自定义线程池 https://www.cnblogs.com/yaoxiaowen/p/6576898.html public ThreadPoolExecutor(int corePool ...

  5. 【Java 并发编程】线程池机制 ( 线程池阻塞队列 | 线程池拒绝策略 | 使用 ThreadPoolExecutor 自定义线程池参数 )

    文章目录 一.线程池阻塞队列 二.拒绝策略 三.使用 ThreadPoolExecutor 自定义线程池参数 一.线程池阻塞队列 线程池阻塞队列是线程池创建的第 555 个参数 : BlockingQ ...

  6. 自定义java线程池_我的Java自定义线程池执行器

    自定义java线程池 ThreadPoolExecutor是Java并发api添加的一项功能,可以有效地维护和重用线程,因此我们的程序不必担心创建和销毁线程,也不必关注核心功能. 我创建了一个自定义线 ...

  7. 我的Java自定义线程池执行器

    ThreadPoolExecutor是Java并发api添加的一项功能,可以有效地维护和重用线程,因此我们的程序不必担心创建和销毁线程,而将精力放在核心功能上. 我创建了一个自定义线程池执行程序,以更 ...

  8. 自定义线程池-参数设计分析

    自定义线程池-参数设计分析 通过观察Java中的内置线程池参数讲解和线程池工作流程总结,我们不难发现,要设计一个好的线程池,就必须合理的设置线程池的4个参数;那到底该如何合理的设计4个参数的值呢?我们 ...

  9. java自定义线程池池,线程池使用及自定义线程池

    一 案例引申 编写代码同时只允许五个线程并发访问(以下文的函数为例子) private static void method() { System.out.println("ThreadNa ...

最新文章

  1. 【ACM】杭电OJ 1789(Doing Homework again)
  2. 二阶系统阶跃响应实验_自控原理二阶系统阶跃响应及性能分析实验报告
  3. CSS完美兼容IE6/IE7/FF的通用方法
  4. oracle: to_char,to_date
  5. 删除链表重复节点 python_java删除链表中重复的节点(保留一个节点)
  6. OpenCv实现两幅图像的拼接
  7. 在lnmp1.3布置的web服务器上运行thinkphp3.2.3项目pathinfo路径模式
  8. GC解释:收集器概述
  9. Gradle2.0用户指南翻译——第二章. 概述
  10. OFFICE工具条的改进
  11. python 有限域函数库_有限域(4)——程序实现有限域的运算
  12. 《Python金融大数据风控建模实战》 第15章 神经网络模型
  13. python绘制国际象棋规则口诀_国际象棋口诀
  14. win10 设备管理器显示便捷设备
  15. 所见即所得的3D打印建模设计
  16. PHP下载文件(laravel)
  17. 2022国产车排行榜前十名
  18. Pytorch——XLNet 预训练模型及命名实体识别
  19. IDL编译器系列-入门篇
  20. 中电资讯-政府工作报告提出2022“金融新任务”;代表共话数字经济;代表提议建立全国统一金融信息数据库

热门文章

  1. ubuntu18.04更换默认下载源为国内清华源、阿里源
  2. 【Java】电子凭证-Java生成PDF
  3. 前端自适应常适配的屏幕大小
  4. 嘉应学院计算机二级考点,2017计算机二级考试MSOffice核考点表格的使用方法
  5. npm install报错,npm WARN ajv-keywords@3.4.0 requires a peer of ajv@^6.9.1 but none is installed. You m
  6. 华为p8高配版android系统版本,华为P8的手机系统是什么?能升级安卓5.0吗?
  7. HTML5新增标签(一)
  8. 解读 Service Mesh 的实现方式与同程艺龙的具体实践
  9. 深圳饿了么java工程师_【饿了么 研发工程师JAVA】-Utips校招-你的名企情报站
  10. oracle 修改字段名称和备注,oracle 修改 字段名称