浅浅了解线程池

news2024/9/24 3:30:09

线程池

  • 1.线程池基本概念(了解)
    • 1.1 什么是线程池
    • 1.2 为什么使用线程池
    • 1.3 线程池的优势
  • 2.创建池的方式
  • 3.线程池的工作原理(重点)
    • 3.1 线程池的七大参数
    • 3.2 线程池的四种拒绝策略
      • AbortPolicy
      • CallerRunsPolicy
      • DiscardPolicy
      • DiscardOldestPolicy
    • 3.3 任务队列
  • 4. 自定义线程池(代码实现)

1.线程池基本概念(了解)

1.1 什么是线程池

线程池其实就是一种多线程的处理方式,处理过程中可以将任务添加到队列里,然后在创建线程后自动启动这些任务,这里的线程就是之前介绍到的线程,这里所说的任务就是实现了RunnableCallable接口的实例对象.

1.2 为什么使用线程池

使用线程池最大的原因就是可以根据系统的需求和硬件环境,灵活的控制线程的数量,且可以对所有线程进行统一的管理和控制,从而提高系统的运行效率,降低系统的运行压力…

1.3 线程池的优势

(1) 降低资源消耗: 通过重复利用已创建的线程降低创建和销毁的消耗.
(2) 提高响应速度: 当任务到达时,任务可以不需要等待线程创建就可以立即执行.

举例:假如创建线程用的时间为T1,执行任务用的时间为T2,销毁线程用的时间为T3,那么使用线程池就免去了T1和T3的时间;

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

2.创建池的方式

序号创建方式解析
AExecutors.newSingleThreadExecutor();创建只有一个线程的线程池
BExecutors.newFixedThreadPool(int nThreads);创建一个固定大小的线程池,容量为n
CExecutors.newCachedThreadPool();创建一个可伸缩的线程池,类似于链表上的结点,可以无限多

大家注意,像这种与并发有关系的API大多在java.util.concurrent包里面

在这里插入图片描述

  • 讲解A — Executors.newSingleThreadExecutor()

创建使用在无界队列上操作的单个工作线程的执行器。(但是请注意,如果这个单线程在关闭之前的执行过程中由于失败而终止,如果需要执行后续任务,将会有一个新的线程取代它。)任务保证按顺序执行,并且在任何给定时间活动的任务不超过一个。

return : 新创建的单线程执行器对象

在这里插入图片描述

源码:

    public static ExecutorService newSingleThreadExecutor() {
    //后面会讲到ThreadPoolExcutor
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, //核心线程数
            						1,//最大线程数
                                    0L,//等待时间
                                    TimeUnit.MILLISECONDS,//时间单位
                                    new LinkedBlockingQueue<Runnable>()));//阻塞队列
    }
  • 讲解B — Executors.newFixedThreadPool(int nThreads)

创建一个线程池,该线程池重用在共享无界队列上操作的固定数量的线程。在任何时候,最多有nThreads线程处于活动状态,正在处理任务。如果在所有线程都处于活动状态时提交额外的任务,它们将在队列中等待,直到一个线程可用。如果任何线程在关闭之前的执行过程中由于失败而终止,如果需要执行后续任务,则会有一个新线程取代它的位置。在显式关闭池之前,池中的线程将一直存在。
参数:
nThreads——池中的线程数
return: 新创建的线程池
抛出异常的条件: IllegalArgumentException -如果nThreads <= 0

在这里插入图片描述
源码:

  public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(
        							  nThreads,//核心线程数
        							  nThreads,//最大线程数(后面讲)
                                      0L,//(先不用管) 
                                      TimeUnit.MILLISECONDS,//(不用管)
                                      new LinkedBlockingQueue<Runnable>());//(阻塞队列)
    }
  • 讲解C — Executors.newCachedThreadPool()

创建一个线程池,该线程池根据需要创建新线程,在以前构造的线程可用时重用它们。这些池通常会提高执行许多短期异步任务的程序的性能。执行调用将重用先前构造的线程(如果可用)。如果没有可用的现有线程,将创建一个新线程并将其添加到池中。60秒内未使用的线程将被终止并从缓存中删除。因此,长时间保持空闲状态的池不会消耗任何资源。

在这里插入图片描述

源码:

   public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0,//核心线程数
        							  Integer.MAX_VALUE,//最大线程数
                                      60L,//如果等待了该时间且还没有用到的线程就会释放
                                      TimeUnit.SECONDS,//时间单位
                                      new SynchronousQueue<Runnable>());//阻塞队列
    }

大家先不要疑惑为什么返回值要用ExecutorService类接收,后面会讲.

3.线程池的工作原理(重点)

3.1 线程池的七大参数

类型参数名描述
intcorePoolSize核心线程池大小
intmaximumPoolSize最核心大线程池大小
longkeepAliveTime超时时间 没有人使用会自动释放
TimeUnitunit超时单位
BlockingQueueworkQueue阻塞队列
ThreadFactorythreadFactory线程工厂,创建线程的,一般不用动
RejectedExecutionHandlerhandler拒绝策略

通过下面情景解析这些属性

public ThreadPoolExecutor(int corePoolSize,//核心线程数
                          int maximumPoolSize,//最大线程数
                          long keepAliveTime,//等待时间
                          TimeUnit unit,//时间单位
                          BlockingQueue<Runnable> workQueue,//阻塞队列
                          ThreadFactory threadFactory,//
                          RejectedExecutionHandler handler)//线程池的拒绝策略
//围绕这些参数看下面的故事
ExecutorService pool = new ThreadPoolExecutor(2,//核心线程数
											  4,//最大线程数
											  30L,//时间,L表示long类型
											  TimeUnit.MINUTES,//单位是分钟
 											  new ArrayBlockingQueue<>(2),//阻塞队列											  
 											  Executors.defaultThreadFactory(),//默认的工厂模式(不重要)
                						   	  new ThreadPoolExecutor.DiscardPolicy())//(锁拒绝策略,这里选择的是丢弃最新任务)

银行开门后,有一个用户A(任务)来办理业务,此时由于没有客服(线程)接待,老板就把客服A喊来上班,当客服A正在给用户A服务时,又进来一位用户B,由于客服A正在忙,所以就把客服B喊来了.现在客服A,B都在为用户办理业务

在这里插入图片描述

此时又来了两位用户,但是客服已经都在忙了,没办法,经理只能从隔壁银行借了两位客服应急,这样才能给这两位新来的用户办理服务.

借来的员工就相当于创建的新线程,但是只能创建两个,因为上面有最大线程数量限制,此时4个员工代表4个线程,正好达到这个界限.

在这里插入图片描述

不久又来了两位用户,但是银行经理看见客服都在帮别人办理业务,于是便说,现在办理业务人比较多,您需要坐在凳子(阻塞队列)上稍等会

两个用户坐在凳子上就想当于阻塞队列内put了两个任务,由于阻塞队列容量为2,所以后续也无法容纳更多的用户.

在这里插入图片描述

当又来一位用户时,经理一看,现在正在办理业务的加上等待办理业务的已经有6位了,银行已经无法再给更多的人进行业务的办理,此时银行经理只能拒绝给这位用户办理业务.

核心线程数-2;最大核心线程数 - 4;阻塞队列 - 2 可容纳最大请求数 - 6
正式员工两位, 最多员工数量四位,椅子只能放两个,所以这家银行最多可以容纳六个用户.

在这里插入图片描述

当处理好所有用户之后,此时又过去了30min,还是没有新来的用户,现在就可以让客服C,D下班了,但是A,B还不可以下班,因为他是这个银行的正式员工.
员工:太惨了QAQ

参数规定30分钟内如果没有新的任务就结束多创建的线程.
30分钟还没有客服,所以给C,D两位借来的员工下班.

在这里插入图片描述

3.2 线程池的四种拒绝策略

拒绝策略描述白话
new ThreadPoolExecutor.AbortPolicy()线程池默认拒绝策略,如果元素添加到线程池失败,会抛出RejectedExecutionException异常劳资已经被你安排的工作压的喘不过气了,你还要再给我别的工作是吧,行,都别过了!!!直接掀桌子(抛异常)
new ThreadPoolExecutor.CallerRunsPolicy()如果添加失败,那么主线程会自己调用执行器中的execute方法来执行任务依旧是自己有很多的任务没完成,此时主管再给我安排任务我就直接跟他说,要做你做,我不做.(谁安排谁做)
new ThreadPoolExecutor.DiscardPolicy()如果添加失败,丢弃最新的任务,也就是刚刚添加的任务,不抛出异常这么多任务我都忙不过来了,你还要给我任务,我直接拒绝!!!(丢弃新添加的任务)
new ThreadPoolExecutor.DiscardOldestPolicy()如果添加到线程池失败,会将队列中最早添加的元素移除,再尝试添加,如果失败则按该策略不断重试不抛异常行,给我安排任务是吧,我做,但是我不能吃亏,我要把在我手里等待时间最久的任务丢弃.(丢弃最老的任务)

下面的举例采用自定义线程池: 核心线程数 – 2,最大线程数 – 8,阻塞队列 – 2 ,可容纳最大请求数量 – 10

AbortPolicy

测试用例 4,10,11

在这里插入图片描述

CallerRunsPolicy

请求数设置为11,不超过最大容量都相同

在这里插入图片描述

DiscardPolicy

在这里插入图片描述

DiscardOldestPolicy

翻译:Oldest = 最古老的
在这里插入图片描述

3.3 任务队列

任务队列是基于阻塞队列实现的,即采用生产者消费者模式,在 Java 中需要实现 BlockingQueue 接口。但 Java 已经为我们提供了 7 种阻塞队列的实现:

  • ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列(数组结构可配合指针实现一个环形队列)。
  • LinkedBlockingQueue: 一个由链表结构组成的有界阻塞队列,在未指明容量时,容量默认为 Integer.MAX_VALUE。
  • PriorityBlockingQueue: 一个支持优先级排序的无界阻塞队列,对元素没有要求,可以实现 Comparable 接口也可以提供 Comparator 来对队列中的元素进行比较。跟时间没有任何关系,仅仅是按照优先级取任务。
  • DelayQueue:类似于PriorityBlockingQueue,是二叉堆实现的无界优先级阻塞队列。要求元素都实现 Delayed 接口,通过执行时间从队列中提取任务,时间没到任务取不出来。
  • SynchronousQueue: 一个不存储元素的阻塞队列,消费者线程调用 take() 方法的时候就会发生阻塞,直到有一个生产者线程生产了一个元素,消费者线程就可以拿到这个元素并返回;生产者线程调用 put() 方法的时候也会发生阻塞,直到有一个消费者线程消费了一个元素,生产者才会返回。
  • LinkedBlockingDeque: 使用双向队列实现的有界双端阻塞队列。双端意味着可以像普通队列一样 FIFO(先进先出),也可以像栈一样 FILO(先进后出)。
  • LinkedTransferQueue: 它是ConcurrentLinkedQueue、LinkedBlockingQueue 和 SynchronousQueue 的结合体,但是把它用在 ThreadPoolExecutor 中,和 LinkedBlockingQueue 行为一致,但是是无界的阻塞队列。

4. 自定义线程池(代码实现)

既然了解了线程池,那么我们自己实现一个精简版的线程池.

写一个for循环,循环的边界由用户指定,每循环一次创建一个线程,在每个线程中使用while(true)来一直读取任务,只要有任务就取,取到任务之后就调用run(),注意:在创建好线程后还需要通过t.start()来启动该线程.

class MyThreadPool{
    //自己实现线程池
    //阻塞队列
    BlockingDeque<Runnable> queue = new LinkedBlockingDeque<>();
    public void submit(Runnable runnable) throws InterruptedException {
        //添加到阻塞队列
        queue.put(runnable);

    }
    public MyThreadPool (int p){
        for (int i = 0; i < p; i++) {
            Thread t = new Thread(()->{
                try {
                    //有任务就取
                    while (true){
                        Runnable runnable = queue.take();
                        runnable.run();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            t.start();
        }
    }

}

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

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

相关文章

提供实习证明和奖学金!面向本科生、研究生的 AI 夏令营!第二期开放报名

无论你是新手还是有AI基础 只要你对AI方向感兴趣&#xff0c;有热情 欢迎你加入Datawhale AI 夏令营 联合科大讯飞、阿里云天池 面向在校本科生、研究生 提供暑期实践学习机会 第二期正式开放报名 线上活动&#xff0c;全程免费 报名时间&#xff1a;2023/7/26 - 2023/8/1 1 关…

​渔网格及多边形网格(蜂窝图)表现空间分布特征

重新排版新发。渔网格及多边形网格(蜂窝图)表现空间分布特征。 练习数据: 爬取的山东省胶东五市文保单位。 先上结果图 1.渔网图表现空间分布特征 整体步骤是先对数据做核密度分析,用渔网工具创建渔网格与点,然后将核密度的值赋至渔网格上,最后进行一系列可视化表达。 …

抖音seo短视频矩阵系统源代码开发技术分享

抖音SEO短视频矩阵系统是一种通过优化技术&#xff0c;提高在抖音平台上视频的排名和曝光率的系统。以下是开发该系统的技术分享&#xff1a; 熟悉抖音平台的算法 抖音平台的算法是通过分析用户的兴趣爱好和行为习惯&#xff0c;对视频进行排序和推荐。因此&#xff0c;开发人员…

HTML+CSS+JavaScript:实现京东秒杀倒计时效果

一、产品需求 下图是京东首页的京东秒杀倒计时 我们将模仿京东倒计时做一个下班倒计时效果&#xff08;如下图&#xff09; 二、代码素材 我先把缺失JS部分的代码放在这里&#xff0c;感兴趣的小伙伴可以先自己试试 <!DOCTYPE html> <html lang"en">&…

ABB机器人与S7-1200PLC实现位置坐标数据发送和接收的具体方法

ABB机器人与S7-1200PLC实现位置坐标数据发送和接收的具体方法 上次和大家分享了ABB机器人与S7-1200 PLC进行Socket通信时的基本设置和简单编程测试,具体可查阅以下链接中的内容: S7-1200与ABB机器人进行SOCKET通信的具体方法 本次继续和大家分享,通过Socket通信(TCP)实现…

DSA之图(3):图的遍历

文章目录 0 图的遍历1 图的遍历方法1.1 深度优先搜索DFS1.1.1 DFS的思想1.1.2 邻接矩阵DFS的实现1.1.3 邻接矩阵DFS的代码实现1.1.4 非连通图的DFS遍历1.1.5 DFS算法效率分析 1.2 广度优先搜索BFS1.2.1 BFS的思想&#xff08;连通图&#xff09;1.2.2 BFS的思想&#xff08;非连…

【机器学习】分类算法 - 模型选择与调优GridSearchCV(网格搜索)

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;零基础快速入门人工智能《机器学习入门到精通》 模型选择与调优 1、交叉验证2、网格搜索3、模型选择与调优API4、案…

IntelliJ IDEA 2023.2 最新变化

主要更新 AI Assistant 限定访问 Ultimate 在此版本中&#xff0c;我们为 IntelliJ IDEA 引入了一项重要补充 – AI Assistant。 AI Assistant 当前具备一组由 AI 提供支持的初始功能&#xff0c;提供集成式 AI 聊天&#xff0c;可以完成一些任务&#xff0c;例如自动编写文档…

在win10上安装spinal hdl完全教程(一篇文章就够了)

一 参考文章 SpinalHDL 开发环境搭建一步到位(图文版) - 极术社区 - 连接开发者与智能计算生态 (aijishu.com)https://aijishu.com/a/1060000000255643SpinalHDL(一)——环境搭建 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/146529005

Android安卓实战项目(4)---提供给阿尔兹海默症患者的APP(源码在文末)

Android安卓实战项目&#xff08;4&#xff09;—提供给阿尔兹海默症患者的APP&#xff08;源码在文末&#xff09; 一.项目运行介绍 1.大致浏览 &#xff08;1&#xff09;开机界面 &#xff08;2&#xff09;主界面 &#xff08;3&#xff09;Read Instructions界面 &…

运维:Windows11操作系统安装VMware16.1.1图文教程(附下载)

目录 一、VMware 16.1.1 介绍 二、安装教程 三、下载地址 一、VMware 16.1.1 介绍 VMware 16.1.1 是一款功能非常强大虚拟化软件&#xff0c;它允许用户在一台计算机上创建和运行多个虚拟机&#xff08;Virtual Machine&#xff09;相当于拥有多台服务器。这些虚拟机可以模拟…

JUC高并发编程(二)——Synchronized关键字

文章目录 前言为什么要用Synchronized关键字 并发编程中的三个问题可见性原子性有序性 Synchronized保证三大特性使用synchronized保证可见性使用synchronized保证原子性用synchronized保证有序性 Synchronized的特征可重入特征不可中断特征 前言 synchronized 关键字&#xff…

Python爬虫时遇到SSL证书验证错误解决办法汇总

在进行Python爬虫任务时&#xff0c;遇到SSL证书验证错误是常见的问题之一。SSL证书验证是为了确保与服务器建立的连接是安全和可信的&#xff0c;但有时候可能会由于证书过期、不匹配或未受信任等原因导致验证失败。为了解决这个问题&#xff0c;本文将提供一些实用的解决办法…

提高业务效率:利用手机号在网状态 API 进行智能筛选

引言 随着科技的不断发展&#xff0c;手机已成为现代人生活中不可或缺的工具。人们通过手机完成通信、娱乐、购物等各种活动&#xff0c;使得手机号成为了一个重要的个人标识。对于企业而言&#xff0c;了解手机号的在网状态对于业务发展和客户管理至关重要。为了提高业务效率…

https和http有什么区别

https和http有什么区别 简要 区别如下&#xff1a; ​ https的端口是443.而http的端口是80&#xff0c;且二者连接方式不同&#xff1b;http传输时明文&#xff0c;而https是用ssl进行加密的&#xff0c;https的安全性更高&#xff1b;https是需要申请证书的&#xff0c;而h…

Linux常用命令——dpkg-statoverride命令

在线Linux命令查询工具 dpkg-statoverride Debian Linux中覆盖文件的所有权和模式 补充说明 dpkg-statoverride命令用于Debian Linux中覆盖文件的所有权和模式&#xff0c;让dpkg于包安装时使得文件所有权与模式失效。 语法 dpkg-statoverride(选项)选项 -add&#xff1…

深度:解密数据库的诗与远方!

‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 不同于历史上的黄金和石油&#xff0c;数据成为了我们新的宝藏&#xff0c;一个驱动社会进步、催生创新的无尽源泉。然而&#xff0c;这些形式各异、复杂纷繁的数据需要一个管理者&#xff0c;一个保险库&#xff0c;一个解…

【动态规划part09】| 198.打家劫舍、213.打家劫舍II、337.打家劫舍III

&#x1f388;LeetCode198.打家劫舍 链接&#xff1a;198.打家劫舍 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷…

【数据结构】实验三:链表

实验三链表 一、实验目的与要求 1&#xff09;熟悉链表的类型定义&#xff1b; 2&#xff09;熟悉链表的基本操作&#xff1b; 3&#xff09;灵活应用链表解决具体应用问题。 二、实验内容 1&#xff09;请设计一个单链表的存储结构&#xff0c;并实现单链表中基本运算算…

基于ssm+mysql+jsp高校疫情防控出入信息管理系统

基于ssmmysqljsp高校疫情防控出入信息管理系统 一、系统介绍二、功能展示1.登陆2.教师管理3.学生管理4.打卡记录管理5.学生申请通行证6.通行证管理7.留言信息管理8.公告类型管理9.公告管理 四、获取源码 一、系统介绍 学生 : 个人中心、打卡记录管理、学生申请通行证、通行证管…