[JAVAee]线程池

目录

线程池的作用

线程池的使用

线程池的创建方式

线程池的解析

①Executors与ThreadPoolExecutor

 ②ThreadPoolExecutor线程池的构造方法

③RejectedExecutionHandler线程池的拒绝策略

固定线程数量线程池的简单模拟实现


线程池的作用

对于线程的使用,可能会频繁的创建与销毁.

但对于这些创建与销毁来说,会产生比较大的开销.因为对于线程的创建与销毁来说,与底层的操作系统息息相关.而像进入操作系统的任务,会被称为"内核态".在内核态当中会执行其他任务,同时内核态中的操作也是我们不可控的,频繁的创建销毁线程需要的成本会更大.

对此,就有了线程池.创造了线程放入"池"中管理,并调用执行一定的任务.在任务完毕后,我们对其并不会进行销毁,而是将其放回到"池"中去.极大的减少了开销.

除了减少了资源的开销,还能对线程在"池"中进行管理.

总结:

  • 减少了资源开销,避免了线程的重复创建与销毁.
  • 增添了对于线程的管理,将线程集中放到一起能够有效的进行管理.
  • 提升了性能,任务对线程的调用响应的速度会增开,还是减少了线程的重复创建与销毁的操作.
  • 限制了线程的个数,防止其无限制的创建.

线程池的使用

在java标准库中,提供了我们使用线程池.

线程池比较特殊,不用去实例化一个类.而是调用了Executors的一个类方法(静态方法)newFixedThreadPool去创建线程池.

返回值为ExecutorService.

ExecutorService pool = Executors.newFixedThreadPool(10);//在线程池中创建10个线程
        pool.submit(new Runnable() {//调用submit方法,给线程们布置任务执行
            @Override
            public void run() {
                System.out.println("wow");
            }
        });
        pool.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("haha");
            }
        });

线程池的创建方式

 在Executors中线程池的创建大致分四种方法.

①newFixedThreadPool-创建固定线程数目的线程池

②newCachedThreadPool-创建线程数目动态增长的线程池

③newSingleThreadExecutor-创建单线程的线程池

④newScheduleThreadPool-创建可延迟执行命令的线程池(类似Timer)

线程池的解析

①Executors与ThreadPoolExecutor

上述对于线程池的创建的四种方法,其实本质上都是同一种方法:ThreadPoolExecutor.

Executors本质上只是对ThreadPoolExecutor类的封装.

源码:

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
//在Exeucutors中实例化了一个ScheduledThreadPoolExecutor,这个类继承了ThreadPoolExecutor

可以看到都ThreadPoolExecutor这个类有关,Executors中不同种类的线程池只是在ThreadPoolExecutor传入的参数不同.

选择了要创建哪一种线程池,在Executor中会默认的帮你设定相应的参数.从而让我们更方便的使用.

 ②ThreadPoolExecutor线程池的构造方法

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
  • corPoolSize-在线程池中的线程数目,即使线程是空闲的.除非设置了allowCoreThreadTimeOut.
  • maximumPoolSize-在线程池中允许的最大线程数目(如果线程池中的任务比较多,会暂时创建新的线程来协助完成任务.但这些新创建的线程最后是会被销毁的,所以有最大线程数=最初创建的线程数 + 临时线程数).
  • keepAliveTime-临时新创建的线程的最大空闲等待新任务的时间,如果时间一到临时创建的线程将会被销毁.
  • unit-keepAliveTime参数的时间单位.
  • workQueue-一个阻塞队列,用来管理任务.
  • threadFactory-工厂模式,辅助线程池创建线程
  • handler-线程池的拒绝策略(下文会介绍)

③RejectedExecutionHandler线程池的拒绝策略

在ThreadPoolExecutor类中,实现了四个拒绝策略

拒绝的是什么?什么时候会触发拒绝条件?

前面我们提到,通过调用创建Executors的实例化对象的submit方法将任务添加到阻塞队列当中.

当任务数量达到一定的数量,队列中塞满了或者线程池中的每一个线程都在工作没有多余的线程时会触发拒绝条件.

AbortPolicy-抛出一个RejectedExecutionException异常

CallRunsPolicy-将被拒绝的任务返回给提交任务的线程执行

DiscardOldestPolicy-抛弃阻塞队列中队首的任务,并把新任务添加进来

DiscardPolicy-抛弃这个想要新加入的任务

固定线程数量线程池的简单模拟实现

分为:

  • 有一个阻塞队列存放任务
  • 创建相应数量的线程
  • 提供一个submit方法添加任务
public class MyThreadPool extends Thread{
    private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();//阻塞队列存放任务

    public MyThreadPool(int n){//构造方法,在创建线程池的时候就创建相应数量的线程
        for(int i = 0; i < n; i++){
            Thread thread = new Thread(() -> {
                while(true){
                    try {
                        Runnable runnable = queue.take();
                        runnable.run();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            thread.start();
        }
    }

    public void submit(Runnable runnable) throws InterruptedException {//将任务存放到阻塞队列的方法
        queue.put(runnable);
    }

    public static void main(String[] args) throws InterruptedException {
        MyThreadPool pool = new MyThreadPool(3);
        pool.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("wowo");
            }
        });
        pool.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("haha");
            }
        });
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

首批!棱镜七彩通过汽车云-汽车软件研发效能成熟度模型能力评估

2023年7月25-26日&#xff0c;由中国信息通信研究院、中国通信标准化协会联合主办的“2023年可信云大会”隆重召开。会上&#xff0c;在中国信息通信研究院云计算与大数据研究所副所长栗蔚的主持下&#xff0c;中国信通院发布了“2023年上半年可信云评估结果”&#xff0c;并由…

uniapp checkbox radio 样式修改

文章目录 通过查看代码&#xff0c;发现 before部分是设置样式的主要属性 我们要设置的话&#xff0c;就要设置checkbox::before的属性。 其中的content表示内容&#xff0c;比如内部的对勾 那么我们设置的时候&#xff0c;比如设置disabletrue的时候或者checkedtrue的时候&…

onnxruntime (C++/CUDA) 编译安装

一、克隆及编译 git clone --recursive https://github.com/Microsoft/onnxruntime cd onnxruntime/ git checkout v1.8.0如果克隆的时候报错&#xff1a; 执行以下&#xff1a; apt-get install gnutls-bin git config --global http.sslVerify false git config --global h…

Git初始化

查看git版本 git --version 设置Git的配置变量 方法&#xff1a; 修改全局文件&#xff08;用户主目录下.gitconfig&#xff09;修改系统文件&#xff08;如/etc/gitconfig&#xff09; 用户姓名和邮件地址 修改用户名和邮件地址 git config --global user.name "用…

《JeecgBoot系列》JeecgBoot(ant-design-vue)实现筛选框:支持下拉搜索+下拉多选+表字典(支持条件查询)功能

JeecgBoot(ant-design-vue)实现筛选框&#xff1a;支持下拉搜索下拉多选表字典(支持条件查询)功能 JSearchMultiSelectTag.vue源文件 一、需求介绍 在使用JeectBoot(ant-design-vue)设计表单时&#xff0c;需要实现下拉搜索下拉多选表字典(支持条件查询)。 但是系统目前有两…

PysparkNote006---pycharm加载spark环境

pycharm配置pyspark环境&#xff0c;本地执行pyspark代码 spark安装、添加环境变量不提了 File-Settings-Project-Project Structure-add content root添加如下两个路径 D:\code\spark\python\lib\py4j-0.10.7-src.zipD:\code\spark\python\lib\pyspark.zip 2023-07-26 阴 于…

linux(进程)[6]

管理概念 先描述&#xff0c;再组织 进程 启动一个软件就相当于启动了一个进程 Linux下执行一条命令就在系统层面创建了一个进程&#xff01;&#xff01; 如何管理 进程对应的代码和数据 进程对应的PCB结构体 PCB&#xff08;process control block&#xff09; 在Linu…

Banana Pi BPI-KVM – 基于 Rockchip RK3568 SoC 的 KVM over IP 解决方案

Banana Pi 已经开始开发基于 Rockchip RK3568 SoC 的 BPI-KVM 盒&#xff0c;但它不是迷你 PC&#xff0c;而是 KVM over IP 解决方案&#xff0c;旨在远程控制另一台计算机或设备&#xff0c;就像您在现场一样&#xff0c;例如能够打开和关闭连接的设备、访问 BIOS 等。 商业…

数据结构之顺序表

一、概念及结构 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构&#xff0c;一般情况下采用数组存 储。在数组上完成数据的增删查改。 顺序表一般可以分为&#xff1a; 1. 静态顺序表&#xff1a;使用定长数组存储元素。 2. 动态顺序表&#xff1a;使用动…

【SEO基础】百度权重是什么意思及网站关键词应该怎么选?

百度权重是什么意思及网站关键词应该怎么选&#xff1f; 正文共&#xff1a;3253字 20图 预计阅读时间&#xff1a;9分钟 ​ 1.什么是网站权重&#xff1f; 这段时间和一些朋友聊到网站权重以及关键词&#xff0c;发现蛮多人对于这两个概念的认知还是存在一些错误的&#xf…

数学分析:流形的线性代数回顾

因为是线性的&#xff0c;所以可以把所有的系数都提取出去。这也是多重线性代数的性质。可以看成基本的各项自变量的乘法。 这里可以看到两个不同基向量下&#xff0c;他们的坐标转化关系。 引出了张量积&#xff0c;也就是前面提到的内容。 对偶空间的例子总是比较美好。 因为…

【EI/SCOPUS会议征稿】第三届物联网与机器学习国际学术会议(IoTML 2023)

第三届物联网与机器学习国际学术会议&#xff08;IoTML 2023&#xff09; 2023 3rd International Conference on Internet of Things and Machine Learning 2023年物联网与机器学习国际学术会议&#xff08;IoTML 2023&#xff09;将于2023年9月15-17日在新加坡召开。会议…

matlab使用教程(5)—矩阵定义和基本运算

本博客介绍如何在 MATLAB 中创建矩阵和执行基本矩阵计算。 MATLAB 环境使用矩阵来表示包含以二维网格排列的实数或复数的变量。更广泛而言&#xff0c;数组为向量、矩阵或更高维度的数值网格。MATLAB 中的所有数组都是矩形&#xff0c;在这种意义上沿任何维度的分量向量的长度…

【Lua学习笔记】Lua进阶——Table(4)继承,封装,多态

文章目录 封装继承多态 封装 // 定义基类 Object {}//由于表的特性&#xff0c;该句就相当于定义基类变量 Object.id 1//该句相当于定义方法&#xff0c;Object可以视为定义的对象&#xff0c;Test可以视为方法名 //我们知道Object是一个表&#xff0c;但是抽象地看&#xff…

Jenkins构建完成后发送消息至钉钉

钉钉群的最终效果&#xff1a; 1、jenkins安装DingTalk插件&#xff0c;安装完成后重启 2、配置钉钉插件 参考官网文档&#xff1a;快速开始 | 钉钉机器人插件 系统管理 拉到最下面&#xff0c;可以看到钉钉配置 按照如下配置钉钉机器人 配置完成可以点击测试按钮&#xff0…

Qt/C++音视频开发50-不同ffmpeg版本之间的差异处理

一、前言 ffmpeg的版本众多&#xff0c;从2010年开始计算的项目的话&#xff0c;基本上还在使用的有ffmpeg2/3/4/5/6&#xff0c;最近几年版本彪的比较厉害&#xff0c;直接4/5/6&#xff0c;大版本之间接口有一些变化&#xff0c;特别是一些废弃接口被彻底删除了&#xff0c;…

Ansible的应用

Ansible简介 Ansible是一个基于Python开发的配置管理和应用部署工具&#xff0c;现在也在自动化管理领域大放异彩。它融合了众多老牌运维工具的优点&#xff0c;Pubbet和Saltstack能实现的功能&#xff0c;Ansible基本上都可以实现。 Ansible能批量配置、部署、管理上千台主机…

Redis(主从复制、哨兵模式、集群)概述及部署

文章目录 一、Redis模式二、Redis 持久化1.Redis 提供两种方式进行持久化&#xff1a;2.RDB 持久化2.1 触发条件2.2 执行流程2.3 启动时加载 3.AOF持久化3.1 执行流程3.1.1 命令追加(append)3.1.2 文件写入(write)和文件同步(sync)3.1.3 文件重写(rewrite) 3.2 文件重写的触发&…

并发编程——线程池

1.概述 如果并发的线程过多&#xff0c;而且执行的时间都非常短&#xff0c;如果这样&#xff0c;每次都要创建线程就会大大降低效率&#xff0c;我们可以通过线程池来解决&#xff0c;JDK5增加了内置线程池ThreadPollExecutor。 2.线程池的优点 1.重复利用&#xff0c;降低…