多线程典型例子(4)——线程池

文章目录

  • 一、线程池的基本情况
  • 1.1、使用线程池的必要性
  • 1.2、线程池为什么比直接在系统中创建线程更高效?
    • 1.2.1、纯内核态操作
    • 1.2.2、纯用户态操作
  • 1.3、那为什么用户态操作比内核态操作更高效?
  • 二、如何在Java中使用线程池
    • 2.1、ExecutorService
    • 2.1、ThreadPoolExecutor[重点]
      • 2.1.1、谈谈Java标准库里的 线程池 构造方法的参数和含义?[经典面试题]
  • 三、自我实现一个线程池
    • 3.1、输入线程数目时如何界定?
      • 3.1.1、CPU密集型
      • 3.1.2、IO密集型

一、线程池的基本情况

1.1、使用线程池的必要性

虽然线程是 “轻量级进程” ,但当我们频繁的创建/销毁 线程时,其所产生的成本不可忽视。因此可以使用 线程池,提前创建好一些线程放在线程池中,后续需要使用线程时,直接从线程池中随取随用即可,当线程不再使用时,就放回池子里。那么此时效率就会大幅度提升。

1.2、线程池为什么比直接在系统中创建线程更高效?

1.2.1、纯内核态操作

但是为什么从线程池中取线程,就比在操作系统里创建线程,更高效呢?
1、如果是从系统处来创建线程,就需要调用系统API,进一步的由系统内核来完成创建线程的操作,譬如说:创建一个PCB,然后再将PCB加入到链表中…(纯内核态操作)

1.2.2、纯用户态操作

2、如果是直接从线程池处获取线程,上述内核态中进行的操作,都已经提前完成了,从线程池中取线程的过程,纯粹是由用户代码完成。(纯用户态)

1.3、那为什么用户态操作比内核态操作更高效?

举个例子:
比如说我们需要去银行办业务,柜台是非工作人员无法进入,此时柜台处就相当于内核态,大众可以在银行大厅随意溜达,此时银行大厅就相当于是用户态。假如A要去柜台让工作人员帮他解冻银行卡,工作人员需要A提供一下身份证复印件来办理业务,但是A没有带复印件,此时工作人员就给出了2个建议:1、工作人员帮他复印。2、银行大厅有复印机,A可以自行进行复印。

如果A让工作人员帮其进行复印,有可能工作人员在帮A复印时,被领导交代了别的比较急的业务(因为内核态是给所有进程提供服务的,工作人员也一样,他也会为很多用户提供服务 ),此时工作人员就会放下手里的复印的工作,先去完成领导交代的业务,过了一会后才继续帮A进行复印。那么此时A就不知道自己什么时候才能拿到复印件,到底是多久,这是不可控的,取决于工作人员的效率,A无法控制。

如果A选择自行到银行大厅进行复印,此时什么时候能复印完,是可控的。

那此时就是A自己复印,比让工作人员帮忙复印,效率会更高更快。

二、如何在Java中使用线程池

2.1、ExecutorService

Java标准库中,提供了现成的线程池类——ExecutorService

ExecutorService 类中提供4个用来 创建线程池对象的过程 的工厂方法:
1、Executors.newFixedThreadPool(int x)
      创建一个固定线程数量的线程池
2、Executors.newCachedThreadPool()
      创建一个线程数目动态变化的线程池:譬如说当首次使用线程池时,线程池可能会没有线程,此时因为要执行任务,就会创建出一个线程,当一个线程不够用时,会动态的创建出其他线程,创建出的线程就不用回收了,以便下次使用。
3、Executors.newSingleThreadPool()
      创建一个只有单个线程的线程池
4、Executors.newScheduleThreadPool()
      包含单个线程的线程池,类似于定时器的效果。添加一些任务,任务都在后续某个时刻再执行,被执行的时候不是只有一个扫描线程来执行任务,可能是由多个线程共同执行所有任务。

Executors 称为 “工厂类”。

public static void main(String[] args) {ExecutorService service = Executors.newFixedThreadPool(4);for(int i = 0;i<1000;i++){/*** 线程池对象创建好了之后,就可以使用 submit() 把任务添加到线程池中*  * 但由于线程池不止要执行一个任务,因此光一个 submit() 还远远不够,* 所以可以在  submit() 外加一个 for循环,1000 表示 有 1000 个任务,* 线程池中的4个线程需要共同执行/分担这1000个任务**/service.submit(new Runnable() {@Overridepublic void run() {System.out.println("Runnable 里的 run() 里,就是我们具体要执行的任务!");}});}}

运行结果:(1000个任务,所以执行了1000下,打印了1000个输出)在这里插入图片描述

2.1、ThreadPoolExecutor[重点]

Java标准库除了提供上述的线程池标准类外,还提供了一个接口更丰富的线程池类—— ThreadPoolExecutor

ThreadPoolExecutor类有4个构造方法:
在这里插入图片描述

2.1.1、谈谈Java标准库里的 线程池 构造方法的参数和含义?[经典面试题]

由于该线程池类 ThreadPoolExecutor 中的线程数并不是一成不变的,而是根据任务的情况动态变化(自适应),如果任务多,该线程池中的线程数就多一些(创建出来),任务少,该线程池中的线程数就少一些(多余的就销毁),但是此处的动态变化也并不是没有限制,因此ThreadPoolExecutor类的构造方法提供了几个不同含义的参数,来对线程池的动态变化产生一定限制。(如:corePoolSize、maximumPoolSize)

1、介绍构造方法中的参数:
      int corePoolSize
核心线程数(线程池里最少也得有这些数量的线程,哪怕线程池里一点任务也没有)

2、int maximumPoolSize
      最大线程数(最多不能超过这些线程。哪怕线程池由于需要执行很多任务忙疯了,动态变化的线程数也不能比这个数目更多了)

举个例子理解上述两个参数:
在这里插入图片描述
这样设定之后,公司繁忙时,就可以在含有正式员工的情况下,招收一些实习生帮忙;在公司不忙的时候,可以将多余的实习生裁掉。

对于线程池来说也是一样,这样的设定,既能保证繁忙的时候高效的处理任务,又能在空闲的时候不会浪费资源。

3、long keepAliveTime
      允许摸鱼的最大时间数(当公司业务不繁忙时,实习生就都空闲下来了,那么公司会立即裁掉实习生吗??不是,是当实习生线程空闲超过指定的时间阈值后,就会被销毁。)

4、TimeUnit unit
      时间单位(譬如 ms、s…)

5、 BlockingQueue workQueue
      线程池内部会有很多任务要线程去执行,这些任务,可以使用阻塞队列来管理起来

6、ThreadFactory threadFactory
      这是一个工厂类,主要用于创建线程的

7、RejectedExecutionHandler handler [考察的重点参数]
      。拒绝方式/拒绝策略。 ThreadPoolExecutor 的线程池,有一个阻塞队列,当阻塞队列中的任务满了之后,继续添加任务,该如何应对??阻塞?不太合适。因此就有了4种拒绝策略:
1)、ThreadPoolExecutor.AbortPolicy
      直接抛出异常,线程池直接不干活了
2)、ThreadPoolExcutor.CallerRunsPolicy
       谁是添加这个新任务的线程,那么这个任务就由谁来执行
3)、ThreadPoolExecutor.DiscardOldestPolicy
      丢弃前边最早的任务,执行新的任务(晚来的任务)。
4)、ThreadPoolExecutor.DiscardPolicy
      直接把最新的任务丢弃了

三、自我实现一个线程池

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;/*** 自我实现一个固定数量的线程池*/
class MyExecutor {private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();public void submit(Runnable runnable) throws InterruptedException {queue.put(runnable);}/*** 线程数** @param n*/public MyExecutor(int n) {for (int i = 0; i < n; i++) {Thread t = new Thread(() -> {while (true) {try {Runnable runnable = queue.take();runnable.run();} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}}
}public class testMyExecutor {public static void main(String[] args) throws InterruptedException {MyExecutor myExecutor = new MyExecutor(4);for (int i = 0; i < 1000; i++) {myExecutor.submit(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"hello");}});}}
}

3.1、输入线程数目时如何界定?

那么创建线程池时,使用创建固定线程数目的线程池的方法时,这个线程池的线程数目究竟是该填几呢?4?8?12?

都不准确。没有什么固定数量!不同项目里,线程要做的工作都是不一样的。有的线程进行的工作是:“CPU密集型”(该线程做的工作大多/全是运算),有的线程的工作是:“IO密集型”(该线程进行的工作可能是:读写文件、等待用户进行输入、网络通信…)。

3.1.1、CPU密集型

"CPU密集型"大部分工作都是要在CPU上执行的,CPU得给线程安排cpu核心去完成工作才行。因此在这个情况下,如果CPU是N个核心,当线程数量也是N时,理想情况下,即每个核心上一个线程,如果有更多线程数,线程只能进行排队等待CPU核心,不会有什么新的进展(譬如说效率提升之类的,不会),甚至于可能物极必反,太多线程数导致线程调度开销变大,影响效率。

3.1.2、IO密集型

“IO密集型”大部分的线程需要进行大量的等待时间,(譬如等待用户进行输入),等的过程中,并没有使用CPU,此时就算线程数就算多一些,也不会给CPU造成太大负担。比如CPU为16个核心,写个32个线程,由于这些线程在进行着“IO密集型”工作,这里大部分的线程都在等,并不消耗CPU,反而CPU的被占用情况还比较低。

但上述描述的是一种 “理想状态”,在实际开发中,既会有部分线程进行 “CPU密集型”工作,又会有部分线程进行“IO密集型”工作。

因此最好的做法就是通过实验(对程序进行性能测试,测试时尝试不同线程数,找到性能和系统资源开销比较均衡的数值)的方式,来找到线程池中合适的线程数目。

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

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

相关文章

OBS插件--自定义着色器

自定义着色器 自定义着色器是一个滤镜插件&#xff0c;可以用于源和场景。插件自带一百多款滤镜效果&#xff0c;支持自己编写效果代码。 下面截图演示下操作步骤&#xff1a; 首先&#xff0c;打开 OBS直播助手 在插件中心左侧导航栏&#xff0c;选择 滤镜 项&#xff0c;然…

【Linux】深浅睡眠状态超详解!!!

1.浅度睡眠状态【S】&#xff08;挂起&#xff09; ——S (sleeping)可中断睡眠状态 进程因等待某个条件&#xff08;如 I/O 完成、互斥锁释放或某个事件发生&#xff09;而无法继续执行。在这种情况下&#xff0c;进程会进入阻塞状态&#xff0c;在阻塞状态下&#xff0c;进程…

C++从入门到入土(二)——初步认识类与对象

目录 前言 类与对象的引入 类的定义 类的访问限定符及封装 访问限定符&#xff1a; 封装&#xff1a; 类的作用域 类的实例化 类的大小 this指针 this指针的特性 前言 各位佬们&#xff0c;在开始本篇文章的内容之前&#xff0c;我想先向大家道个歉&#xff0c;由于…

linux中进程相关概念(一)

什么是程序&#xff0c;什么是进程&#xff0c;有什么区别&#xff1f; 程序是静态的概念&#xff0c;当我们使用gcc xxx.c -o pro进行编译时&#xff0c;产生的pro文件&#xff0c;就是一个程序。 进程是程序的一次运行活动&#xff0c;通俗点就是说程序跑起来了就是进程。 …

利用智能私信软件,快速拓展潜在客户群体

在数字化营销的浪潮中&#xff0c;企业如何快速而有效地触及并吸引潜在客户&#xff0c;已成为一个不可忽视的挑战。随着人工智能技术的不断进步&#xff0c;智能私信软件作为一种新型工具&#xff0c;正逐渐改变着企业的市场拓展方式。本文将探讨如何通过这类软件&#xff0c;…

RBAC 权限设计(五)

序言 本文介绍 RBAC2 模型以及具体的实现方案。本文仅提供实现思路供大家参考&#xff0c;在生产实践中请根据业务场景进行具体设计。 一、RBAC2 模型 RBAC2 是 RBAC&#xff08;基于角色的访问控制&#xff09;模型中的一种&#xff0c;它在 RBAC0 的基础上&#xff0c;对用…

GitHub中Asterank源码python修改成C++(本人python不太会)

GitHub - typpo/asterank: asteroid database, interactive visualizations, and discovery tools 主要目的是在进行多元线性回归的时候将枚举型转换为数值型 python: # # The constants used in calculations for the values of asteroids. ## General constants GENERAL_I…

学习torchmd分子动力学模拟

TorchMD打算提供一种简单易用的API&#xff0c;用于使用PyTorch进行分子动力学。这使研究人员能够更快地进行力场开发研究&#xff0c;并以PyTorch的简单性和强大性将神经网络潜力无缝集成到动力学中。 TorchMD使用与经典MD代码&#xff08;如ACEMD&#xff09;一致的化学单位&…

引入OSS

前置条件 AccessKey 引入依赖 都是官网上的&#xff1a;https://help.aliyun.com/zh/oss/developer-reference/java-installation?spma2c4g.11186623.0.i16 <!--若是创建项目的时候这个依赖勾选了就不用了--><!--不加启动会报错No active profile set, falling back…

JavaScript之数据类型(2)——复杂类型(object)

object的介绍&#xff1a; 我对于object的理解是和C/C中的结构体一样&#xff0c;是一个自定义的数据类型&#xff0c;我们可以通过多个简单的数据类型来定义一个便于我们使用的新的数据类型。 在网上某佬对于其解释如下&#xff1a; Object类型&#xff0c;我们也称为一个对象…

Windows命令行一键安装、配置WSL的方法

本文介绍在Windows电脑中&#xff0c;通过命令行的方式&#xff0c;快速、方便安装适用于Linux的Windows子系统&#xff08;Windows Subsystem for Linux&#xff0c;WSL&#xff09;的方法。 WSL是由微软开发的一项功能&#xff0c;允许在Windows操作系统上运行Linux发行版系统…

【Linux的文件篇章 - 磁盘文件】

Linux学习笔记---012 Linux之进程程序替换理解1、磁盘文件1.1、文件如何存取的问题1.2、了解磁盘的存储结构1.3、如何找到指定位置的扇区&#xff1f;1.4、对磁盘的存储进行逻辑抽象(了解OS对磁盘这样的硬件设备的抽象与管理) 2、磁盘级文件系统2.1、Linux文件系统特定2.2、文件…

Ansible--Templates 模块 Tags模块 Roles模块

一 Templates 模块 ①Jinja是基于Python的模板引擎。Template类是Jinja的一个重要组件&#xff0c;可看作一个编译过的模 板文件&#xff0c;用来产生目标文本&#xff0c;传递Python的变量给模板去替换模板中的标记。 ②在配置文件中&#xff0c;会有一些数据&#xff08;如…

Java毕设之基于SpringBoot的在线拍卖系统

运行环境 开发语言:java 框架:springboot&#xff0c;vue JDK版本:JDK1.8 数据库:mysql5.7(推荐5.7&#xff0c;8.0也可以) 数据库工具:Navicat11 开发软件:idea/eclipse(推荐idea) 系统详细设计 管理员功能模块 管理员登录&#xff0c;管理员通过输入用户名、密码、角色等信…

UE4_Water插件_Buoyancy组件使用

water插件提供了一个浮力Actor蓝图类。 需要注意的几个问题&#xff1a; 1、StaticMesh需要替换根组件。 2、需要模拟物理设置质量。 3、需要添加浮力组件&#xff0c;设置浮力点&#xff0c;应用水中牵引力。 4、最重要的是需要激活——自动启用。 5、调水波长的地方 双击图片…

FreeRTOS学习 -- 任务相关API函数

一、任务创建和删除API函数 FreeRTOS 最基本的功能就是任务管理&#xff0c;而任务管理最基本的操作就是创建和删除任务。 FreeRTOS的任务创建和删除API函数如下&#xff1a; 1、函数 xTaskCreate() 此函数用来创建一个任务&#xff0c;任务需要 RAM 来保存于任务有关的状…

前端js面试题--从字符串中删除删除注释代码

问题&#xff1a;从字符串中删除删除注释代码 描述&#xff1a; solution(weex,rex # and react\nflutter\nnative ssss !hybrid app, [#, !]) 写一个solution函数清除后面参数数组里面的字符串 打印效果 代码1 思路&#xff1a; 将字符全凡是有去掉标志符号的全部添加\n…

Java_File

介绍&#xff1a; File对象表示路径&#xff0c;可以是文件&#xff0c;也可以是文件夹。这个路径可以是存在的&#xff0c;也可以是不存在的&#xff0c;带盘符的路径是绝对路径&#xff0c;不带盘符的路径是相对路径&#xff0c;相对路径默认到当前项目下去找 构造方法&…

基于SSM的校园短期闲置资源置换平台(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的校园短期闲置资源置换平台&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过…

燃气电力瓶装气行业入户安检小程序开发

我们开发的小区业主入户安检小程序&#xff0c;旨在满足燃气、电力以及其他需要入户安检的行业需求。该程序支持自定义安检项目&#xff0c;实现线下实地安检与线上数据保存的完美结合。在安检过程中&#xff0c;我们可以拍照或录像&#xff0c;以确保安检的透明性和可追溯性&a…