Java线程池个人整理笔记

news2024/11/16 6:32:13

一、线程池有哪些优点


总体来说,线程池有如下的优势:

(1)降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

(2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。

(3)提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
 

二、线程池的主要参数

线程池ThreadPoolExecutor的继承关系

想知道有哪些参数,先看参数最多的构造函数:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

可以看到创建一个线程池需要七个参数。

  1. corePoolSize:线程池核心线程数量大小,有新任务进来时,如果线程池中的线程数小于这个值,则会创建新的线程来执行任务(不管有没有空闲线程,都会创建),直到线程数量大于等于这个数量。
  2. maximumPoolSize:线程池最大线程数量大小(当达到核心线程数,且队列任务已满,会增加线程至最大线程数)。
  3. keepAliveTime:线程的最大空余时间,大于这个时间将被回收(线程数大于核心线程数时,多余的线程空闲时长达到这个值就会被回收)。
  4. unit:空余时长的单位。
  5. workQueue:阻塞队列,当核心线程数已满,任务会被放到这个队列中。
  6. threadFactory:线程工厂,线程池中的线程都是由这个线程工厂创建的,线程池提供了默认的线程工厂。
  7. handler:拒绝策略,当队列任务已满,且线程数量达到最大线程数,新进入的任务会执行这个拒绝策略来选择丢弃哪个任务,线程池提供了四种默认的拒绝策略。

线程工厂ThreadFactor,线程池中默认给定了一个线程工厂DefaultThreadFactory,线程工厂的作用是用于创建线程,自己创建线程工厂时需要实现ThreadFactor接口,该接口中只有一个方法Thread newThread(Runnable r);,即创建线程的方法,自定义线程工厂的好处是可以自定义线程名称。

阻塞队列BlockingQueue,阻塞队列是在核心线程满了以后存放任务使用,常用的有LinkedBlockingQueueArrayBlockingQueueSynchronousQueueDelayedWorkQueue等,当阻塞队列也满时,会创建线程至最大线程数,如果队列已满,也达到最大线程数,则执行拒绝策略。

拒绝策略RejectedExecutionHandler

  • DiscardPolicy:丢弃该任务,不抛异常。
  • DiscardOldestPolicy:丢弃最早加入队列的任务,不抛异常。
  • AbortPolicy:丢弃该任务并抛出异常RejectedExecutionException,默认使用该策略。
  • CallerRunsPolicy:由调用线程池的线程来执行当前任务。

查看源码:

public static class DiscardPolicy implements RejectedExecutionHandler {
    public DiscardPolicy() { }
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    }
}
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
    public DiscardOldestPolicy() { }
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            e.getQueue().poll();
            e.execute(r);
        }
    }
}
public static class AbortPolicy implements RejectedExecutionHandler {
    public AbortPolicy() { }
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        throw new RejectedExecutionException("Task " + r.toString() +
                                             " rejected from " +
                                             e.toString());
    }
}
public static class CallerRunsPolicy implements RejectedExecutionHandler {
    public CallerRunsPolicy() { }
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        if (!e.isShutdown()) {
            r.run();
        }
    }
}

如果想要实现自己的拒绝策略,那么实现RejectedExecutionHandler接口即可。

三、线程池的执行流程

如下图:

查看源码执行流程,execute()方法:

public void execute(Runnable command) {
    //传入的任务是否为空
    if (command == null)
        throw new NullPointerException();
    /*
     * Proceed in 3 steps:
     *
     * 1. 如果运行的线程数小于corePoolSize,则创建新的线程(线程池状态为正在运行的状态)。
     *
     * 2. 如果任务排队成功,仍然需要检查线程池的状态,如果不是可运行的状态则回滚刚刚的操作。
     *
     * 3. 如果排队失败,则尝试添加新的线程,如果已经达到线程池最大数量,则执行拒绝策略。
     */
     //判断线程数是否小于核心线程数
    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        //如果小于,新增一个线程来执行
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    //如果核心线程数已满,则向阻塞队列中添加任务
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    //如果添加失败,则创建线程至最大值
    else if (!addWorker(command, false))
        //如果创建失败,则执行拒绝策略
        reject(command);
}

四、线程池的状态

查看源码,发现线程池有五种状态,如下:

// runState is stored in the high-order bits
private static final int RUNNING    = -1 << COUNT_BITS;
private static final int SHUTDOWN   =  0 << COUNT_BITS;
private static final int STOP       =  1 << COUNT_BITS;
private static final int TIDYING    =  2 << COUNT_BITS;
private static final int TERMINATED =  3 << COUNT_BITS;
  1. RUNNING,运行状态,线程池创建完成后就是运行状态。
  2. SHUTDOWN,关闭状态,执行shutdown()方法后进入此状态,继续处理队列中的任务,但是不再接收新的任务。
  3. STOP,停止状态,shutdownNow()方法后进入此状态,不处理队列中的任务,也不接收新的任务。
  4. TIDYING,整理状态,运行的线程数为0,队列中任务为空时,则进入此状态,进入此状态后会执行terminated()方法,进入销毁状态。
  5. TERMINATED,销毁状态,执行terminated()方法,进入此状态。

状态转换如下图:

五、Java提供的快速创建的线程池

Executors提供了几种快速创建的线程池:

  • newSingleThreadExecutor,只有一个线程的线程池
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
  • newFixedThreadPool,固定线程数量的线程池
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
  • newCachedThreadPool,可缓存的线程池,即不限制线程数量的线程池。
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
  • newScheduledThreadPool,定时线程池,可周期性或延迟执行任务的线程池(使用延时队列)。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
}
  • newSingleThreadScheduledExecutor,单个线程的定时线程池,功能和上面一样。
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
    return new DelegatedScheduledExecutorService
        (new ScheduledThreadPoolExecutor(1));
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/192928.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

配置Linux18.04系统/解决无法安装vmwatools的问题

一、解决无法安装vmwatools的问题 1.关闭虚拟机中的Linux18.04系统 2.打开虚拟机设置 3.修改所有的CD/DVD 、软盘 连接为&#xff1a;使用物理驱动器->自动检测&#xff08;如下图&#xff09; 4.打开虚拟机&#xff0c;都点是&#xff1b; 5.解决解压桌面上的vmware-…

春节特献!一文纵览2022年全球量子计算行业要闻!

&#xff08;图片来源&#xff1a;网络&#xff09;岁聿云暮&#xff0c;一元复始。如果说2018年是量子计算技术变革元年&#xff0c;那么2022年全球量子计算已正式步入市场探索加速期。随着中国、美国、欧盟等国家相继出台各种量子信息相关战略纲要和旗舰计划&#xff0c;越来…

数据的解析的介绍(1)

1.xpath 注意&#xff1a;提前安装xpath插件 &#xff08;1&#xff09;打开chrome浏览器 &#xff08;2&#xff09;点击右上角小圆点 &#xff08;3&#xff09;更多工具 &#xff08;4&#xff09;扩展程序 &#xff08;5&#xff09;拖拽xpath插件到扩展程序中 &#xff0…

王道操作系统笔记(五)———— 经典同步问题

前言&#xff1a;PV 操作题目分析步骤 关系分析&#xff1a; 找出题目中描述的各个进程&#xff0c;分析它们之间的同步、互斥关系。整理思路&#xff1a; 根据各进程的操作流程确定 P、V 操作的大致顺序。设置信号量&#xff1a; 并根据题目条件确定信号量初值。&#xff08;…

数据结构与算法基础——栈和队列

栈只能在表尾进行插入删除操作 队列先进先出 队列和栈都是线性表&#xff0c;不过是插入和删除的 位置被限制了。 队列头进尾出

Dubbo 入门系列之基于 Dubbo API 开发微服务应用

目标 从零上手开发基于 Dubbo 的微服务 难度 低 环境要求 系统&#xff1a;Windows、Linux、MacOS JDK 8 及以上&#xff08;推荐使用 JDK17&#xff09; Git IntelliJ IDEA&#xff08;可选&#xff09; Docker &#xff08;可选&#xff09; 动手实践 本章将通过手把…

网络编程-UDP数据报套接字

专栏简介: JavaEE从入门到进阶 题目来源: leetcode,牛客,剑指offer. 创作目标: 记录学习JavaEE学习历程 希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长. 学历代表过去,能力代表现在,学习能力代表未来! 目录 1. 网络编程基础 1.1 为什么需要网络编程? 1.2 什…

好友关注-Feed流实现方案

9.3 好友关注-Feed流实现方案 当我们关注了用户后&#xff0c;这个用户发了动态&#xff0c;那么我们应该把这些数据推送给用户&#xff0c;这个需求&#xff0c;其实我们又把他叫做Feed流&#xff0c;关注推送也叫做Feed流&#xff0c;直译为投喂。为用户持续的提供“沉浸式”…

简聊商城项目的表设计

零、前言 1、优惠卷设计 电商项目中的优惠券系统这样设计&#xff0c;同事直呼 666 &#xff01; 2、SPU和SKU的定义及他们之间的关系 SPU全称Standard Product Unit&#xff0c;即标准化产品单元。 简单理解就是某一种产品。 SKU全称Stock Keeping Unit&#xff0c;即库存量…

ChatGPT官方API可以抢先体验了

ChatGPT官方API目前还在内测当中&#xff0c;OpenAI官网上也没有任何接口介绍和文档。这对于开发和调用来说不怎么方便。但是&#xff0c;比较好的地方在于内测过程中调用是免费的&#xff0c;没有次数限制。此外&#xff0c;API接口调用不需要梯子或代理&#xff08;使用代理反…

【原创】如何做一张原创8BIT音乐的NES音乐卡片

我陷入了深思。。。。。。 第一步是创作一首8BIT音乐。我介绍两个NES用的音乐工具&#xff1a;FamiTracker 和 FamiStudio。 选FamiTracker的原因是&#xff0c;有完美教程呀。红鸡将他的教程放到B站了&#xff1a;红激教你做音乐 一共11集&#xff0c;非常亲民地道的教学&a…

C++11 lambda表达式

作者&#xff1a;小萌新 专栏&#xff1a;C进阶 作者简介&#xff1a;大二学生 希望能和大家一起进步&#xff01; 本篇博客简介&#xff1a;介绍C11的lambda表达式 lambda表达式lambda表达式的概念lambda表达式语法lambda表达式交换两个数lambda表达式的底层原理lambda表达式的…

【ChatGPT 中文版小程序】无需注册体验 ChatGPT 的攻略

本文导读什么是ChatGPT&#xff1f;ChatGPT能做什么&#xff1f;功能测试如何解锁有趣功能&#xff1f;我想部署同样的一个小程序&#xff0c;请问如何做&#xff1f;什么是ChatGPT&#xff1f; 最近网上非常火爆的CHATGPT&#xff0c;它是OpenAI开发的一款开源的自然语言处理…

专访量子计算上市公司IonQ CEO

&#xff08;图片来源&#xff1a;网络&#xff09;IonQ的CEO Peter Chapma&#xff0c;从70年代中期就从事高科技行业&#xff0c;至今已有45年左右。在接受媒体采访时&#xff0c;Peter Chapman谈到IonQ扩展计算机和提供业务价值的计划、量子客户的最佳应用程序开发合作伙伴、…

DEFCON议题解读|Dll劫持新思路——修改环境变量

简介 在2022年的Defcon大会上,安全研究人员Wietze Beukema通过对进程级环境变量的研究&#xff0c;提出了一种Dll劫持新思路&#xff0c;下面就其中涉及的技术点展开介绍。 **01 **环境变量 每一个进程都有一个环境块&#xff0c;其中包含一组环境变量及其值。有两种类型的环…

RabbitMQ的消息模型

文章目录1、简单队列2、work 模式3、发布/订阅模式4、路由模式FanoutDirect5、主题模式6.工作模式总结7、四种交换器RabbitMQ官方提供了5个不同的Demo示例&#xff0c;对应了不同的消息模型&#xff1a; 1、简单队列 一个生产者对应一个消费者&#xff01;&#xff01; publi…

Linux shell 命令行环境下使用阿里云盘

阿里云盘在内测的时候我就在使用&#xff0c;整体体验相当的好&#xff0c;最起码不会限速&#xff0c;比起下载速度只有十几 KB 的某垃圾云盘要强太多了。 当然除了使用各系统的客户端进行下载之外&#xff0c;我还想要在命令行进行操作&#xff0c;主要原因也是我有一台 NAS…

AcWing 487. 金明的预算方案(有依赖的背包问题 + 分组背包问题)

AcWing 487. 金明的预算方案一、问题二、分析三、代码一、问题 二、分析 这道题属于一个背包问题&#xff0c;但是这道题中有一个很神奇的条件。就是我们想要购买某个物品的附件的话&#xff0c;前提是我们要购买这个物品的主件。 因此&#xff0c;我们可以将这道题画成下面这…

Java高手速成 | EL表达式语言

本文主要讲解EL表达式语言的作用、基本语法以及运算符。 01、EL的作用 当需要在JSP页面显示变量以及JavaBean对象时&#xff0c;可以使用JSP的表达式&#xff0c;如<%变量%>的形式&#xff0c;也可以直接使用如<%out.println(变量)%>的Java输出语句。尤其当JSP页…

C语言学习笔记-循环

有的时候&#xff0c;我们可能需要多次执行同一块代码。一般情况下&#xff0c;语句是按顺序执行的&#xff1a;函数中的第一个语句先执行&#xff0c;接着是第二个语句&#xff0c;依此类推。 编程语言提供了更为复杂执行路径的多种控制结构。 循环语句允许我们多次执行一个…