多线程 - 线程池

news2024/10/6 10:33:34

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() {
                @Override
                public 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() {
                @Override
                public void run() {
                    System.out.println("hello " + n);
                }
            });
        }
    }
}

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

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

相关文章

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

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

dockerfile lnmp 搭建wordpress、docker-compose搭建wordpress

-----------------安装 Docker--------------------------- 目前 Docker 只能支持 64 位系统。systemctl stop firewalld.service setenforce 0#安装依赖包 yum install -y yum-utils device-mapper-persistent-data lvm2 --------------------------------------------------…

什么是信创测试?信创测试工具有哪些?

信创全称是“信息技术应用创新”&#xff0c;旨在实现信息技术自主可控&#xff0c;规避外部技术制裁和风险&#xff0c;其涉及产业链包括硬件、基础软件、应用软件、云服务、数据安全等领域。 信创测试是指对信创工程项目中的产品、系统等进行测试和验证&#xff0c;以确保其…

【B/S架构】医院不良事件报告系统源码

医院不良事件报告系统为医院内质量控制、患者安全关注、医疗安全不良事件方面的精细化的管理提供了平台&#xff0c;是等级医院评审的必备内容&#xff0c;评审要求医院直报系统要与卫生部“医疗安全(不良)事件报告系统”建立网络对接。 不良事件报告系统源码包括护理相关事件、…

写一个名为Rectangle的类表示矩形

如何使用Rectangle类计算矩形的面积 要求&#xff1a;其属性包括宽width、高height和颜色color&#xff0c;访问权限分别为private&#xff0c;width和height都是double型的&#xff0c;而color则是String类型的。要求该类提供计算面积的方法getArea()方法&#xff0c;以及修改…

Node.js 做 Web 后端的优势在哪?为什么是明智的选择?

当我们谈论构建强大的Web应用程序时&#xff0c;选择适当的后端技术至关重要。在如今的技术领域中&#xff0c;Node.js已经崭露头角&#xff0c;并且越来越多的开发者和企业选择将其作为首选的后端开发工具。但是&#xff0c;Node.js究竟有哪些优势&#xff0c;使得它成为众多开…

WMS仓储管理系统的盘点功能解析

随着电商行业的快速发展&#xff0c;仓储管理在企业的运营中扮演着越来越重要的角色。为了提高仓库的运营效率和管理水平&#xff0c;许多企业引入了WMS仓储管理系统。本文将对WMS仓储管理系统的盘点功能进行解析&#xff0c;探讨其在实际应用中的价值。 一、WMS仓储管理系统概…

【分享】影刀使用xpath捕获指定的元素

xpath捕获元素比较精准&#xff0c;前面也介绍了xpath的用法 现在捕获社区里帖子详情页的标题 //*[class‘discuss_detail_header___3LhnQ’]/h1 找到class是discuss_detail_header___3LhnQ的子元素h1 获取文章内容 //*[id‘w-e-textarea-1’] 找到id是w-e-textarea-1的元…

这短短 6 行代码你能数出几个bug?

前言&#xff1a;本文仅仅只是分享笔者一年前见到的诡异代码&#xff0c;大家可以看看乐子&#xff0c;随便数一数一共有多少个bug&#xff0c;这数bug多少还是要点水平的 在初学编程的时候&#xff0c;写的第一个代码大多都是 hello world&#xff0c;可是就算是 hello world…

如何使用CSS和JavaScript实施暗模式?

近年来&#xff0c;暗模式作为用户界面选项备受追捧。它提供了更暗的背景和更亮的文本&#xff0c;不仅可以减轻眼睛疲劳&#xff0c;还可以节省电池续航时间&#xff0c;尤其是在OLED屏幕上。 不妨了解如何结合使用CSS和JavaScript为网站和Web应用程序添加暗模式选项。 了解暗…

因果图测试用例设计方法介绍(超全的总结笔记错过就没有了)

前言 为什么需要测试用例 测试的目的是在有限的资源下&#xff0c;尽可能多的找出系统的缺陷。这就要求在测试中&#xff0c;尽可能完全的走完系统的所有流程&#xff0c;保证所有的分支都经过测试。 而测试过程是由人来执行的&#xff0c;不可能避免的会遗漏一些应该测试内容…

新增TOP!10月SCI/SSCI/EI刊源表已更新!

2023年10月SCI/SSCI/EI期刊目录更新 2023年10月份刊源表已更新&#xff01;计算机领域新增TOP期刊、SSCI、EI新增多本好刊&#xff0c;重点期刊如下&#xff0c;相关领域作者注意投稿截止时间&#xff01; 01 计算机领域 02 医学与制药领域 03 工程综合领域 04 环境生物化学地…

uniapp实现扫一扫功能,扫码成功后跳转页面

uniapp官方有提供的相关api实现跳转到web网页(h5)的功能,在开发小程序中,是一项很常见的功能开发。该功能使用到的api uni.scanCode 详细步骤如下: 1.在ui库中找到扫码icon,以uViewUI为例 绑定点击事件@click <u-icon class="scanIcon" name="scan…

Maven 项目文档

本章节我们主要学习如何创建 Maven 项目文档。 比如我们在 C:/MVN 目录下&#xff0c;创建了 consumerBanking 项目&#xff0c;Maven 使用下面的命令来快速创建 java 项目&#xff1a; mvn archetype:generate -DgroupIdcom.companyname.bank -DartifactIdconsumerBanking -…

含冰蓄冷空调的冷热电联供型微网多时间尺度优化调度

MATLAB代码&#xff1a;含冰蓄冷空调的冷热电联供型微网多时间尺度优化调度 关键词&#xff1a;冰蓄冷空调 CCHP-MG 多时间尺度优化 冷热电联供 参考文档&#xff1a;《含冰蓄冷空调的冷热电联供型微网多时间尺度优化调度》完全复现 仿真平台&#xff1a;MATLAB yalmipcplex…

PowerShell install 一键部署hfish

hfish前言 HFish是一款社区型免费蜜罐,侧重企业安全场景,从内网失陷检测、外网威胁感知、威胁情报生产三个场景出发,为用户提供可独立操作且实用的功能,通过安全、敏捷、可靠的中低交互蜜罐增加用户在失陷感知和威胁情报领域的能力。 HFish具有超过40种蜜罐环境、提供免费…

修改了windows dns配置,在wsl2中不生效

本地做测试环境&#xff0c;需要劫持dns解析&#xff0c;所以在本地搭dns解析服务&#xff0c;用来劫持域名解析流量&#xff0c;需要将本地dns服务器地址配到127.0.0.1&#xff0c;如图&#xff0c;但是 wsl 中&#xff0c;却没有变化&#xff0c;依然是原来的dns&#xff0c;…

Unity基础课程之物理引擎3-碰撞检测案例-吃金币并加分显在UI文本框上

业务逻辑&#x1f4bc;&#xff1a; 这个脚本的主要功能是用于显示和更新主角的得分。在游戏中&#xff0c;玩家需要吃到金币来增加分数&#xff0c;而这个脚本就是负责将得分的变化实时显示在屏幕上的。 程序逻辑&#x1f4bb;&#xff1a; 1️⃣首先&#xff0c;在脚本的开始…

python实战案例 —— 获取 淘 商品数据

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 开发环境: python 3.8 pycharm 专业版 第三方库: requests >>> pip install requests 模块安装&#xff1a; win R 输入cmd 输入安装命令 pip in…

kafka 开启认证授权

前言 1、前面自己写了一篇关于各个环境各个模式的安装的文章&#xff0c;大家可以去看看 kafka各种环境安装(window,linux,docker,k8s),包含KRaft模式 2、使用版本 kafka_2.13-3.4.1 3、kafka验证方式&#xff0c;有两大类如下&#xff0c;文档内容在 kafka官方文档的 第七节…