线程 -- 线程池

线程池

谈起线程池之前,我们可以联想到常量池,那什么是常量池呢?

常量池:字符串常量,在 Java 程序最初构建的时候,就已经准备好了。等程序运行的时候,这样的常量也就加载到内存中了。因此剩下了构造/销毁的开销。

其实,在计算机中, 这个词,就只有这一个意思,表示的含义都是一样的 。

线程池,就是为了让我们高效的创建销毁线程的。我们不妨想想最初引入线程的原因:频繁创建销毁进程,太慢了。

随着互联网的发展,随着我们对性能的要求更进一步,咱们现在觉得,频繁创建销毁线程,开销有些不能接受了。解决方案有两个:1.线程池 2. 协程(纤程,轻量级线程)。

所以,线程池其实就是:把线程提前创建好,放到一个地方(放到类似于数组),需要用的时候,随时去取,用完了还回到池子中。

但是,其实还有小问题~~

为啥我们认为,直接创建线程开销比从池子里取线程更大呢???

这里我们就不得不说一下操作系统的 用户态 和 内核态 了。

一个操作系统 = 内核 + 配套的应用程序

  • 内核是包含操作系统的各种核心功能

    1)管理硬件设备。

    2)给软件提供稳定的运行环境

一个操作系统,内核就是一份,一份内核,要给所有的应用程序提供服务支持的。

如果有一段代码是应用程序中自行完成的,则整个执行过程是可控的。

如果有一段代码,需要进入到内核中,由内核负责完成一系列工作,这个过程是不可控的,咱们程序员写的代码干预不了。

因此,通常认为,可控的过程要比不可控的过程更高效。

从线程池取现成的线程,纯应用程序代码就可以完成。【可控】

从操作系统创建新的线程,就需要操作系统内核配合完成。【不可控】

所以使用线程池,就可以省下应用程序切换到内核中运行这样的开销。

Java标准库也提供了直接使用的线程池(ThreadPoolExecutor -> 线程池里准备好一些线程,让这些线程执行一些任务)

核心方法,submit(Runnable),通过Runnable描述一段要执行的任务。

通过submit任务放到线程池中,此时线程池里的线程会执行这样的任务。

但有一个比较重要的是,构造这个类的时候,构造方法,比较麻烦。(参数有点多)

而且,Java的线程池,里面包含几个线程,是可以动态调度的。任务多的时候,自动扩容成更多的线程,任务少的时候,把额外的线程干掉,节省资源。
在这里插入图片描述
此处,这里讲一下最后一个,因为他的参数最多。都含上面的参数。
在这里插入图片描述

  • int corePoolSize 核心线程数 -> 至少有多少个线程,线程池一创建,这些线程也要随之创建。直到整个线程池销毁,这些线程才会销毁。

  • int maximumPoolSize 最大线程数 -> 最大线程 + 非核心线程(自适应) 就是不繁忙就销毁,繁忙就在创建。(当然,线程也不是越多越好)

    举个例子:我们可以简单的理解成 线程池 => 公司, 核心线程 => 正式员工 , 非核心线程 => 实习生。需要的时候就招聘实习生,不需要的时候就裁掉。但是呢,正式员工不敢乱裁,如果赔偿不到位,劳动仲裁就够喝一壶。

  • long keepAliveTime 非核心线程允许空闲的最大时间 也就是允许实习生摸鱼的时间,如果实习生连续一个月都没有啥活了,就可以考虑优化掉。

  • TimeUnit unit 枚举

  • BlockingQueue workQueue 工作队列选择使用数组/链表,指定capacity,指定是否要带有优先级/比较规则)线程池,本质上也是 生产者消费者模型调用submit就是在生产任务,线程池里的线程就是在消费任务。

  • ThreadFactory threadFactory 给线程提供的工厂类(统一的构造并初始化线程),工厂模式 (也是一种设计模式,和单例模式是并列的关系)-> 用来弥补构造方法的缺陷的。 线程中有一些属性可以设置,线程池是一组线程。

  • ※RejectedExecutionHandler handler 拒绝策略(整个线程池七个参数中,最重要的,最复杂的)。submit把任务添加到任务队列中(任务队列就是阻塞队列),队列满了,再添加,就阻塞。(一般不希望程序阻塞太多)。对于线程池来说,发现入队列操作时,队列满了,不会真的触发“入队列操作”,不会真阻塞,而是执行拒绝策略相关代码。 如果调用submit就阻塞(业务逻辑中的线程调用submit)就会使这个线程就没办法干别的事情了,不是一个好的选择。

(这个线程要响应用户的请求,阻塞了,用户迟迟拿不到请求的响应,用户等很久,直观上看到的现象 是“卡了”,与其是“卡了”不如告诉直接我“失败”)
在这里插入图片描述

工厂模式

工厂模式是Java中常用的设计模式之一,它主要用于创建对象,同时将对象的创建和使用过程分离,提高了代码的可维护性和可拓展性。工厂模式主要有三种类型:简单工厂模式,工厂方法模型和抽象工厂模式。这里就拿简单工厂模式举例。
简单工厂模式,又称为静态工厂模式,通过一个工厂类根据传入的参数决定创建哪种类型的对象。这种模式的优点是易于理解和实现,但缺点是随着产品类的增加,工厂类的代码也需要修改,这违反了开闭原则。(对扩展开放,对修改关闭)。
就比如,我想在一个平面上创建一个点,我们可以用极坐标表示这个点,也可以用平面坐标系来表示。
在这里插入图片描述

但是由于这两个构造方法的个数,参数类型相同,无法构成重载。所以,对于这种情况,我们就需要用工厂模式来解决这种情况。(C++和Java共有的一个问题:构造方法的名字是固定的,想要提供不同的版本,就需要通过重载,有时候不一定能构成重载),我们创建一个工厂类,来对 目标对象 进行实例化,工厂类来对 目标对象 进行初始化。
在这里插入图片描述

其中,
在这里插入图片描述

称为工厂方法。
提供工厂方法的类称为工厂类。
工厂方法的核心,通过静态方法,把构造对象 new 的过程,各种属性初始化的过程,封装起来了。提供多组静态方法,实现不同情况的构造。

Executors

在Java标准库,也提供了另一组类,针对 ThreadPoolExecutor 进行了进一步封装,简化线程池的使用,也是基于工厂设计模式。
在这里插入图片描述

  • 使⽤ Executors.newFixedThreadPool(10) 能创建出固定包含 10 个线程的线程池。
  • 返回值类型为 ExecutorService。
  • 通过 ExecutorService.submit 可以注册⼀个任务到线程池中。
Executors 创建线程池的⼏种⽅式:

newFixedThreadPool: 创建固定线程数的线程池(核心线程数和最大线程数一样)
newCachedThreadPool: 创建线程数⽬动态增⻓的线程池.(最大线程数是一个很大的数字(线程可以无限增加))
newSingleThreadExecutor: 创建只包含单个线程的线程池.
newScheduledThreadPool: 设定 延迟时间后执⾏命令,或者定期执⾏命令. 是进阶版的 Timer.
Executors 本质上是 ThreadPoolExecutor 类的封装

实现固定线程个数的线程池
  • 核⼼操作为 submit, 将任务加⼊线程池中
  • 使⽤ Worker 类描述⼀个⼯作线程. 使⽤ Runnable 描述⼀个任务.
  • 使⽤⼀个 BlockingQueue 组织所有的任务
  • 每个 worker 线程要做的事情: 不停的从 BlockingQueue 中取任务并执⾏
    (线程池,最核心的就是submit 这样的操作,往线程池中,添加任务(任务就是Runnable)。得有线程来执行队列中的任务,所以我们在构造方法中,把线程创建处来,随时有新的任务要被添加进去,咱们的线程就需要持续不断的尝试读取任务,然后取到了就执行,没取到就阻塞等待)
    在这里插入图片描述
    在这里插入图片描述

在执行的时候我们会发现虽然100 个任务完成了,但进程并没有结束
在这里插入图片描述

这是因为线程池里的这些线程,还在take阻塞的(等待),线程池中的线程,是前台线程,阻止进程结束。
shutdown 能够把线程池里的线程全部关闭,但是不能保证线程池内的任务一定能全部执行完毕。
所以,如果需要等待线程池内的任务全部执行完毕,需要调用 awaitTermination 方法。

(线程池最主要的还是解决服务器这边的开发的问题,上古时期,服务器如何处理多个客户端的请求?基于多进程的模型。每次有个客户端请求过来了,服务器这边都创建一个 进程 给这个客户端提供服务(读取请求,解析请求,返回响应…)后来,频繁创建销毁进程,效率比较低,引入了线程,模型就成了,每个客户端都分配一个线程,提供服务。但随着客户端越来越多,发现频繁创建销毁线程,这个事情也变得比较低效了,又引入了线程池。线程池里,提前准备好了 10 个线程,有100个客户端把请求发过来,把这100个客户端的请求,封装成 任务(Runnable)添加到线程池里,线程池中有着 10 个线程负责处理这 100 个任务,这个过程就不涉及线程的创建销毁了)。

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

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

相关文章

uniapp-原生android插件开发摘要

uni-app在App侧的原生扩展插件,支持使用java、object-c等原生语言编写,从HBuilderX 3.6起,新增支持了使用uts来开发原生插件。 基础项目 UniPlugin-Hello-AS工程请在App离线SDK中查找 基础项目(App离线SDK)已经配置好了自定义插件所需要的…

Hive-05之查询 分组、排序、case when、 什么情况下Hive可以避免进行MapReduce

一、目标 掌握hive中select查询语句中的基本语法掌握hive中select查询语句的分组掌握hive中select查询语句中的join掌握hive中select查询语句中的排序 二、要点 1. 基本查询 注意 SQL 语言大小写不敏感SQL 可以写在一行或者多行关键字不能被缩写也不能分行各子句一般要分行…

MacDroid for Mac v2.3 安卓手机文件传输助手 支持M、Intel芯片 4.7K

MacDroid 是Mac毒搜集到的一款安卓手机文件传输助手,在Mac和Android设备之间传输文件。您只需要将安卓手机使用 USB 连接到 Mac 电脑上即可将安卓设备挂载为本地磁盘,就像编辑mac磁盘上的文件一样编辑安卓设备上的文件,MacDroid支持所有 Andr…

题解:洛谷 P2199 最后的迷宫

题目https://www.luogu.com.cn/problem/P2199 显然,数据最大 ,数组我们开不下,动态开数组。 对于每一个查询,从起点开始,走一步判断是否能看到火焰杯。 如果已经没法走了,直接拆墙,输出 Poor…

如何在Github上面上传本地文件夹

前言 直接在GitHub网址上面上传文件夹是不行的,需要一层一层创建然后上传,而且文件的大小也有限制,使用Git进行上传更加方便和实用 1.下载和安装Git Git - Downloads 傻瓜式安装即可 2.获取密钥对 打开自己的Github,创建SSH密钥&…

vscode接入ai插件(免费版)

一、安装插件 扩展程序搜索tongyilingma 点击install安装 二、登录阿里云 安装好之后左侧会出现通义的图标。 点击通义图标,右上角登录。 登陆成功后即可使用。 三、位置 在左边可能不太符合编码习惯,我们点击右侧位置图标,把通义图标拖…

【deepseek第二课】docker部署dify,配置私有化知识库,解决网络超时,成功安装

【deepseek第二课】docker部署dify,配置私有化知识库,解决网络超时,成功安装 1. dify安装1.1 官网安装文档介绍1.2 安装报错,网络连接问题使用镜像加速器处理1.3 dify后台启动很多docker进程2. 页面探索2.1 设置管理账号2.2 添加ollama支持的模型3. 创建知识库4. 创建一个聊…

如何利用SpringSecurity进行认证与授权

目录 一、SpringSecurity简介 1.1 入门Demo 二、认证 ?编辑 2.1 SpringSecurity完整流程 2.2 认证流程详解 ?2.3 自定义认证实现 2.3.1 数据库校验用户 2.3.2 密码加密存储 2.3.3 登录接口实现 2.3.4 认证过滤器 2.3.5 退出登录? 三、授权 3.1 权限系统作用 …

非平稳时间序列分析(二)——ARIMA(p, d, q)模型

此前篇章(平稳序列): 时间序列分析(一)——基础概念篇 时间序列分析(二)——平稳性检验 时间序列分析(三)——白噪声检验 时间序列分析(四)—…

【软考-架构】1.2、指令系统-存储系统-cache

GitHub地址:https://github.com/tyronczt/system_architect ✨资料&文章更新✨ 指令系统 计算机指令执行过程:取指令一一分析指令一一执行指令三个步骤,首先将程序计数器PC中的指令地址取出,送入地址总线,CPU依据…

家用可燃气体探测器——家庭燃气安全的坚实防线

随着社会的发展和变迁,天然气为我们的生活带来了诸多便利,无论是烹饪美食,还是温暖取暖,都离不开它的支持。然而,燃气安全隐患如影随形,一旦发生泄漏,可能引发爆炸、火灾等严重事故,…

鸿蒙 ArkUI 实现敲木鱼小游戏

敲木鱼是一款具有禅意的趣味小游戏,本文将通过鸿蒙 ArkUI 框架的实现代码,逐步解析其核心技术点,包括动画驱动、状态管理、音效震动反馈等。 一、架构设计与工程搭建 1.1 项目结构解析 完整项目包含以下核心模块: ├── entry…

分布式日志和责任链路

目录 日志问题 责任链问题 分布式日志 GrayLog简介 部署安装 收集日志 配置Inputs 集成微服务 日志回收策略 搜索语法 搜索语法 自定义展示字段 日志统计仪表盘 创建仪表盘 链路追踪 APM 什么是APM 原理 技术选型 Skywalking简介 部署安装 微服务探针 整合…

进程间通信(IPC)与匿名管道

目录 一、进程间通信(IPC)概述 1. 核心概念 2. 核心目的 3. IPC分类 二、匿名管道 1. 什么是管道 示例:Shell中的管道 2. 匿名管道的原理 3. 匿名管道的实现 3.1 创建管道:pipe()函数 3.2 使用 fork 共享管道 3.3 站在…

构建智能 SQL 查询代理agent,把整个查询过程模块化,既能自动判断使用哪些表,又能自动生成 SQL 语句,最终返回查询结果

示例代码: import os import getpass from dotenv import load_dotenv from pyprojroot import here from typing import List from pprint import pprint from pydantic import BaseModel from langchain_core.tools import tool from langchain_core.runnables i…

从矩阵乘法探秘Transformer

目录 前言1. transformer背景1.1 回顾线性代数的知识1.1.1 矩阵和行向量1.1.2 矩阵相乘和算子作用1.1.3 从分块矩阵的乘法来看 Q K T V QK^TV QKTV 1.2 encoder-decoder1.3 低阶到高阶语义向量的转换1.4 核心的问题 2. transformer网络结构2.1 基于KV查询的相似性计算2.2 在一个…

用友NC系列漏洞检测利用工具

声明!本文章所有的工具分享仅仅只是供大家学习交流为主,切勿用于非法用途,如有任何触犯法律的行为,均与本人及团队无关!!! 目录标题 YongYouNcTool启动及适配环境核心功能界面预览一键检测命令执…

MacBook Pro使用FFmpeg捕获摄像头与麦克风推流音视频

FFmpeg查看macos系统音视频设备列表 ffmpeg -f avfoundation -list_devices true -i "" 使用摄像头及麦克风同时推送音频及视频流: ffmpeg -f avfoundation -pixel_format yuyv422 -framerate 30 -i "0:1" -c:v libx264 -preset ultrafast -b:v 1000k -…

zookeeper-docker版

Zookeeper-docker版 1 zookeeper概述 1.1 什么是zookeeper Zookeeper是一个分布式的、高性能的、开源的分布式系统的协调(Coordination)服务,它是一个为分布式应用提供一致性服务的软件。 1.2 zookeeper应用场景 zookeeper是一个经典的分…

【数据结构】LRUCache|并查集

目录 一、LRUCache 1.概念 2.实现:哈希表双向链表 3.JDK中类似LRUCahe的数据结构LinkedHashMap 🔥4.OJ练习 二、并查集 1. 并查集原理 2.并查集代码实现 3.并查集OJ 一、LRUCache 1.概念 最近最少使用的,一直Cache替换算法 LRU是Least Recent…