多线程 - 线程池

v2-d063475533f419d1183152a0252a44ee_1440w

线程池

相关的背景知识

线程池存在的意义: 使用进程来实现并发编程,效率太低了,任务太重了,为了提高效率,此时就引入了线程,线程也叫做“轻量级进程”,创建线程比创建进程更高效;销毁线程比销毁进程更高效;调度线程比调度进程更高效…此时,使用多线程就可以在很多时候代替进程来实现并发编程了.

俗话说,有对比就有伤害,线程和进程比,确实是有优势的,不过,随着并发程度的提高,我们对于性能要求标准的提高,就发现,线程的创建也没有那么轻量…当需要频繁创建销毁线程的时候,就发现,好像开销还是挺大的…想要进一步的再提高这里的效率,程序猿们就想出了两种办法:

  1. 弄一个“轻量级线程” => 协程/纤程(问题是这个东西目前还没有被加入到java标准库,无法使用)
    注: GO语言就内置了协程,因此使用Go开发并发编程程序是有一定优势的,这也是GO语言这么火的原因之一.
    • go属于语法层面支持协程
    • Java是第三方库层面上支持协程C++是标准库层面上支持
    • Python是语法层面支持…
  2. 使用线程池,来降低创建/销毁线程池的开销.
    线程池比如: 字符串常量池,数据库连接池
    事先把需要使用的线程创建好,放到"池”中.后面需要使用的时候,直接从池里获取.
    如果用完了,也还给池,这两个“动作”比创建/销毁更高效的.

为什么这两个“动作”比创建/销毁更高效的?

创建线程/销毁线程,涉及到用户态内核态之间的切换,它的创建是交由操作系统内核完成的,也就是在内核态完成的.
从“池”获取/还给“池”,是用户代码就能实现的(纯粹的用户态操作),不必交给内核操作.

一个操作系统 = 内核+配套的应用程序
内核 => 操作系统最核心的功能模块集合
配套的应用程序 => 硬件管理,各种驱动,进程管理,内存管理,文件系统…
内核需要给上层应用程序提供支持
例子: println("hello") => 应用程序调用系统内核,告诉内核,我要进行一个打印字符串操作,内核再通过驱动程序,操作显示器,完成上述功能

对“用户态”和“内核态”的理解:

image-20231009144310707

标准库中的线程池

在Java标准库中,给我们提供了现成的线程池,可以直接进行使用.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** Created with IntelliJ IDEA.* Description:* User: fly(逐梦者)* Date: 2023-10-08* Time: 20:53*/
public class ThreadDemo26 {public static void main(String[] args) {// 创建了一个线程池,池子里现成数目固定是 10 个.ExecutorService pool = Executors.newFixedThreadPool(10);// 这个操作,使用Executors类的某个静态方法,直接构造出一个对象来 ~~ (相当于是把 new 操作,给隐藏到这样的方法后面了)// 像这样的方法,就称为"工厂方法"// 提供这个工厂方法的类,也就称为"工厂类"// 此处这个代码就使用了“工厂模式"这种设计模式for (int i = 0; i < 1000; i++) {int n = i; // 变量捕获pool.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello" + n);}});}// 线程池提供的 submit 方法,可以给线程池提交若干个任务/** 运行程序之后发现, main 线程结束了,但是整个进程没结束* 线程池中的线程都是 前台线程 , 此时会组织进程结束.(前面定时器 Timer 也是同理)* */}
}

工厂模式

image-20231009145956193

这个操作.使用某个类的某个静态方法,直接构造出一个对象来(相当于是把 new操作,给隐藏到这样的方法后面了)
像这样的方法,就称为"工厂方法",提供这个工厂方法的类,也就称为“工厂类",此处这个代码就使用了“工厂模式"这种设计模式
“工厂模式": 一句话表示,使用普通的方法,来代替构造方法,创建对象.
“工厂模式”,是用来填构造方法的坑的 ~~ 唉,无奈之举!!!
例子: 假设现在有个类,来表示平面上的一个点,第一种构造方法使用笛卡尔坐标系提供的坐标,来构造点,第二种构造方法使用极坐标系提供的坐标,来构造点,
image-20231009164222226

正常来说,多个构造方法是通过"重载”的方式来提供的.重载的要求是,方法名相同,参数的个数或者类型不相同.所以,上述的两个构造方法是无法构成重载的,代码是会编译报错的.

重载(overload)和重写(override)的区别
重载(overload): 这两个方法在同一个类里是可以构成重载,分别在父类子类里,也是可能构成重载的.
重写(override): 在 Java中,方法重写是和父类子类相关的(如果是其他语言,重写方法不一定通过父类子类),本质上就是用一个新的方法,代替旧的…就得要求新的方法和旧的方法,名字/参数都得一模一样才行.

为了解决上述的这个问题,就可以使用“工厂模式”.
image-20231009170506362

备注:

  1. ExecutorService pool = Executors.newCachedThreadPool();创建的线程池,不会设定固定值,按需创建,用完之后也不会立即销毁,留着以后备用.Executors.newCachedThreadPool()Executors.newFixedThreadPool(10)和相关的工厂方法,其实都是基于ThreadPoolExecutor的封装.
  2. 其实很多设计模式,和“工厂模式”一样,也都没什么难度.只是名字听起来高大上,其实并不是什么高深莫测的东西.很多时候,设计模式,是在规避编程语言语法上的坑.
    不同的语言,语法规则不一样.因此在不同的语言上,能够使用的设计模式,可能会不同.有的设计模式,已经被融合在语言的语法内部了…日常见到的设计模式,主要是基于C++/Java/C#这样语言来展开的,这里所说的设计模式不一定适合其他语言,工厂模式,就对于Python来说没什么价值 ~~ Python构造方法,不像C++ / Java的这么坑,它可以直接在构造方法中通过其他手段来做出不同版本的区分…

image-20231009173545839

注: 官方文档,非常重要,学习过程中,要经常去翻这个文档!!

变量捕获

image-20231010004105221

在Java 中,对于变量捕获,做了一些额外的要求.在JDK 1.8之前,要求变量捕获,只能捕获 final修饰的变量.后来发现,这么做太麻烦了.在JDK1.8开始,放松了一点标准,要求不一定非得带 final关键字,只要代码中没有修改这个变量,也可以捕获.

image-20231010005710959

注: Java 的变量捕获要有不可修改的要求,但是 C++, JS 也有类似的变量捕获的语法,但是没有上述限制.

image-20231010012528922

ThreadPoolExecutor类的构造方法详解

image-20231010095225482

实际开发的时候,线程池的线程数,设定成多少合适呢?

网上的一些资料的答案: N(CPU的核数), N + 1,1.5N, 2N ……不过以上这些答案都不对. 线程池的线程数的设定多少合适是没有具体的数字的,因为不同的程序特定不同,此时要设置的线程数也是不同的.
考虑两个极端情况:
1.CPU 密集型,每个线程要执行的任务都是狂转CPU(进行一些列算术运算),此时线程池的线程数,最多不应该超过 CPU 核数.此时如果设置更多的线程数,也起不到作用,CPU密集型任务,要一直占用CPU,过多创建的线程,CPU根本调度不来.
2.IO 密集型,每个线程做的工作就是等待 IO(读写硬盘,读写网盘,等待用户输入……),此时,线程是不“吃”CPU的,因为这样的线程处于阻塞状态,不参与CPU调度……这个时候线程池多创建一些线程是可以的,不会再收制于CPU核数了.理论上来说,现在线程数设置无穷大都可以,当然,现实会因为系统的资源不够而失败.

不过,实际开发中并没有程序符合这两种理想模型…真实的程序,往往一部分要吃CPU,一部分要等待IO
具体这个程序几成工作量是吃CPU的,几成工作量是等待IO,是不确定的………
实际确定线程数量,是试出来的,通过测试/实验的方式(实践是检验真理的唯一标准).

小知识: 现在的CPU,是一个物理核心上可以有多个逻辑核心的.
8核16线程 => 8个物理核心,每个物理核心上有两个逻辑核心,每个逻辑核心同一时刻只能处理一个线程
一般情况下,对于我们程序猿来说,谈到CPU核心数指的就是逻辑核心.

线程池的“拒绝策略”

image-20231010111915034

实现线程池

~~ 自己写代码实现固定数量线程的线程池
一个线程池,里面至少有两个大的部分
1.阻塞队列,保存任务
2.若干个工作线程.

相关代码

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;/*** Created with IntelliJ IDEA.* Description: 实现简单线程池 ~~ 实现固定数量的线程池* User: fly(逐梦者)* Date: 2023-10-9* Time: 11:55*/
class MyThreadPool {// 此处只有任务,就直接使用 Runnable 即可private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();// n 表示线程的数量public MyThreadPool(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) {throw new RuntimeException(e);}}});t.start();}}// 注册任务给线程池public void submit(Runnable runnable) {try {queue.put(runnable);} catch (InterruptedException e) {throw new RuntimeException(e);}}}public class ThreadDemo27 {public static void main(String[] args) {MyThreadPool pool = new MyThreadPool(10);for (int i = 0; i < 1000; i++) {int n = i;pool.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello " + n);}});}}
}

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

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

相关文章

为什么通过一致性正则化方法就可以避免将所有未标记数据集分配给同一类?

一致性正则化方法可以帮助避免将所有未标记数据分配给同一类别的原因在于它们引入了对模型输出的一致性约束&#xff0c;从而减轻了判别性损失&#xff08;如交叉熵损失&#xff09;可能导致的问题。以下是一些关键原因&#xff1a; 一致性反馈&#xff1a; 一致性正则化方法…

Go语言中向[]byte数组中增加一个元素

要向http.Request的body中添加一个键值对&#xff0c;可以先将其转换为一个map&#xff0c;然后对其进行修改&#xff0c;最后再将其转回为byte数组。 以下是一个示例代码&#xff1a; import ("net/http""io/ioutil""encoding/json" )type Re…

在美国如何申请批准销售儿童玩具?提交哪些相关文件?需要的认证是?

在美国如何申请批准销售儿童玩具&#xff1f;提交哪些相关文件&#xff1f;需要的认证是&#xff1f;ASTM F963-17 ​在美国销售玩具 重要&#xff1a; 如果您要在亚马逊商城销售商品&#xff0c;则必须遵守适用于这些商品和商品信息的所有联邦、州和地方法律以及亚马逊政策。…

iNet Network Scanner for Mac,轻松管理网络

iNet Network Scanner for Mac是一款强大的网络扫描工具&#xff0c;能够帮助你轻松管理和监控网络设备。 无论你是个人用户还是企业管理员&#xff0c;iNet Network Scanner都能为你提供全面而方便的网络管理体验。它可以快速扫描并识别局域网中的所有设备&#xff0c;包括电…

使用 html2canvas 和 jspdf 将页面转 pdf,同时解决当页面过长时,页面白屏问题

代码如下&#xff0c;直接粘贴复制即可&#xff0c;代码中 jspdf 是全局引入&#xff0c;你可以自己局部引入 别人使用标签的方式来显示 base64&#xff0c;但是当页面过长时&#xff0c;base64 大小过大会导致页面解析异常&#xff0c;显示白屏 import html2canvas from html2…

【Linux】常驻内核和虚拟内存的区别

常驻内存和虚拟内存是计算机内存管理的两个概念。 常驻内存指的是应用程序在运行时&#xff0c;所占用的内存空间不会随着应用程序的启动和关闭而有所变化&#xff0c;这种内存是常驻在计算机的物理内存中的。即使我们关闭了电脑&#xff0c;这些程序也会保持在内存中&#xf…

Rocky(centos)安装nginx并设置开机自启

一、安装nginx 1、安装依赖 yum install -y gcc-c pcre pcre-devel zlib zlib-devel openssl openssl-devel 2、去官网下载最新的稳定版nginx nginx: downloadhttp://nginx.org/en/download.html 3、将下载后的nginx上传至/usr/local下 或者执行 #2023-10-8更新 cd /usr/…

自动求导,计算图示意图及pytorch实现

pytorch实现 x1 torch.tensor(3.0, requires_gradTrue) y1 torch.tensor(2.0, requires_gradTrue) a x1 ** 2 b 3 * a c b * y1 c.backward() print(x1.grad) print(y1.grad) print(x1.grad 6 * x1 * y1) print(y1.grad 3 * (x1 ** 2))输出为&#xff1a; tensor(36.) …

数据库连接性比较:Navicat 和基于 Java 的工具

在数据库管理和开发领域&#xff0c;工具的选择可以极大地提高效率和生产力。基于Java的工具已成为强有力的竞争者&#xff0c;为数据库工作提供多样化的功能。然而&#xff0c;当谈及原生数据库连接性时&#xff0c;工具间的差异性可能会产生很大的影响。让我们一起来探索 Nav…

MyBatis(JavaEE进阶系列4)

目录 前言&#xff1a; 1.MyBatis是什么 2.为什么要学习MyBatis框架 3.MyBatis框架的搭建 3.1添加MyBatis框架 3.2设置MyBatis配置 4.根据MyBatis写法完成数据库的操作 5.MyBatis里面的增删改查操作 5.1插入语句 5.2修改语句 5.3delete语句 5.4查询语句 5.5like查…

Pytorch笔记之回归

文章目录 前言一、导入库二、数据处理三、构建模型四、迭代训练五、结果预测总结 前言 以线性回归为例&#xff0c;记录Pytorch的基本使用方法。 一、导入库 import numpy as np import matplotlib.pyplot as plt import torch from torch.autograd import Variable # 定义求…

web基础及http协议

web基础 全称 world wide web 全球广域网也就是万维网 web1.0 只能看 web2.0 页面交互&#xff1a;静态页面和动态页面 静态页面url&#xff1a;文本文件&#xff0c;可以修改&#xff0c;一般以html .htm保存的文本文件。网站的基础。静态页面和后台数据库没有任何交互不包含…

阿里云/腾讯云国际站:私服服务器:什么是游戏虚拟服务器及用途讲解?

游戏虚拟服务器是一种新兴的技术&#xff0c;它可以为玩家提供更好的游戏体验。私服服务器它可以将游戏服务器的负载分散到多台服务器上&#xff0c;从而提高游戏的流畅度和稳定性。此外&#xff0c;游戏虚拟服务器还可以提供更多的游戏功能&#xff0c;比如游戏聊天室、游戏排…

如何下载IEEE Journal/Conference/Magazine的LaTeX/Word模板

当你准备撰写一篇学术论文或会议论文时&#xff0c;使用IEEE&#xff08;电气和电子工程师协会&#xff09;的LaTeX或Word模板是一种非常有效的方式&#xff0c;它可以帮助你确保你的文稿符合IEEE出版的要求。无论你是一名研究生生或一名资深学者&#xff0c;本教程将向你介绍如…

一站式工单系统哪家好?一站式工单系统有什么特点?

伴随着高新科技的不断发展和行业竞争的加重&#xff0c;对于一站式工单系统这一类的公司服务系统软件有着越来越多的流程规定和可靠性的要求。一个比较完善的智能化一站式工单系统包含众多的流程&#xff0c;并适用更广泛性的企业信息化&#xff0c;接下来我们将一起看看一站式…

如何才能在Ubuntu系统部署RabbitMQ服务器并公网访问

在Ubuntu系统上部署RabbitMQ服务器并公网访问&#xff0c;可以按照以下步骤进行&#xff1a; 安装RabbitMQ服务器&#xff1a; 在终端中输入以下命令安装RabbitMQ服务器&#xff1a; sudo apt-get update sudo apt-get install rabbitmq-server启动RabbitMQ服务器&#xff1a; …

数字孪生与GIS数据为何高度互补?二者融合后能达到什么样的效果?

山海鲸可视化作为一款数字孪生软件&#xff0c;在GIS的融合方面处于业内领先水平&#xff0c;那么为什么一款数字孪生软件要花费巨大的精力&#xff0c;去实现GIS的融合&#xff0c;实现后又能达到什么样的效果呢&#xff1f;下面就让我们来一探究竟。 一、为什么数字孪生需要…

iview表格 异步修改列数据卡顿 滚动条失效

使用表格row-key属性 将row-key属性设置为true <Table ref"table" border :row-key"true" :columns"tableColumns" :loading"loading":data"tableData"></Table>

Java之UDP,TCP的详细解析

练习四&#xff1a;文件名重复 public class UUIDTest { public static void main(String[] args) { String str UUID.randomUUID().toString().replace("-", ""); System.out.println(str);//9f15b8c356c54f55bfcb0ee3023fce8a } } public class Client…

【K8S系列】深入解析k8s 网络插件—kube-router

序言 做一件事并不难&#xff0c;难的是在于坚持。坚持一下也不难&#xff0c;难的是坚持到底。 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记论点蓝色&#xff1a;用来标记论点 在现代容器化应用程序的世界中…