【Java|多线程与高并发】线程池详解

news2024/9/22 23:22:07

文章目录

  • 1. 线程池简介
  • 2. 创建线程池
  • 3. 工厂模式简介
  • 4. 线程池的使用
  • 5. 实现线程池
  • 6. ThreadPoolExecutor的构造方法讲解
  • 7. 线程池的线程数量,如何确定?

在这里插入图片描述

1. 线程池简介

Java线程池是一种用于管理和重用线程的机制,它可以在需要执行任务时,从线程池中获取线程,执行任务,然后将线程放回池中,以便后续使用。线程池可以有效地管理线程的数量,提高程序的性能和资源利用率。

为什么从线程池里面取线程比直接创建线程快呢?

创建线程是要在操作系统内核中完成的,涉及"用户态"到"内核态"切换操作. 这个切换是有一定开销的. 而线程池取线程是纯的用户态实现.

2. 创建线程池

注意这里线程池创建的写法:

ExecutorService executorService = Executors.newCachedThreadPool();

这里并没有new,而是通过Executors的静态方法newCachedThreadPool来创建的,这里涉及到一种设计模式-“工厂模式”

3. 工厂模式简介

工厂模式(Factory Pattern)是一种创建对象的设计模式,它提供了一种封装对象创建过程的方式,使得客户端代码与具体对象的实例化过程解耦。

工厂模式的主要目的是通过一个工厂类来创建对象,而不是直接在客户端代码中使用new关键字来实例化对象。这样可以隐藏具体对象的创建细节,提供更灵活、可扩展的设计。

详细可参考:工厂模式 | 菜鸟教程

4. 线程池的使用

线程池的使用很简单,只需要实现submit方法即可

public class Demo19 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程执行的任务1");
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程执行的任务2");
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程执行的任务3");
            }
        });
    }
}

这里主要是将任务放到线程池中,线程池里的线程就会去执行这些任务

运行结果:

在这里插入图片描述

5. 实现线程池

要想实现线程池,要先弄清楚线程池有哪些功能.

一个线程池中可以同时提交N个任务,线程池里有M个线程来执行这N个任务

如何将N个任务分配给M个线程呢?

可以使用生产者-消费者模型解决这个问题.

以下是一个线程池的简易实现:

public class MyThreadPool {
    private BlockingQueue<Runnable> blockingQueue = new public class MyThreadPool {
    private BlockingQueue<Runnable> blockingQueue = new LinkedBlockingQueue<>();

    public void submit(Runnable runnable) throws InterruptedException {
        // 将任务添加到阻塞队列中
        blockingQueue.put(runnable);
    }

    public MyThreadPool(int m){
        // 创建m个线程
        for (int i = 0; i < m; i++) {
            Thread t = new Thread(() ->{
                // 让它一直扫描阻塞队列
                while (true) {
                    try {
                        // 取出任务,并执行
                        Runnable runnable = blockingQueue.take();
                        runnable.run();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
            t.start();
        }
    }
}

测试上述代码:

public class Demo20 {
    public static void main(String[] args) throws InterruptedException {
        MyThreadPool pool = new MyThreadPool(5);
        for (int i = 0; i < 10; i++) {
            int temp = i;
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("任务"+ temp);
                }
            });
        }
    }
}

运行结果:

在这里插入图片描述

不过上述代码中创建的线程数量是"固定"的,可根据需要自行调整

6. ThreadPoolExecutor的构造方法讲解

ThreadPoolExecutor是Java中线程池的一个具体实现类,它实现了ExecutorService接口。ExecutorService是一个高级的线程池管理接口,提供了更多的灵活性和功能。

ThreadPoolExecutor这个类的构造方法比较复杂
在这里插入图片描述

参数:

  • corePoolSize - 即使空闲时仍保留在池中的线程数,除非设置 allowCoreThreadTimeOut

  • maximumPoolSize - 池中允许的最大线程数

  • keepAliveTime - 当线程数大于内核时,这是多余的空闲线程在终止前等待新任务的最大时间。

  • unit - keepAliveTime参数的时间单位

  • workQueue - 用于在执行任务之前使用的队列。 这个队列将仅保存execute方法提交的Runnable任务。(自己传入的任务队列,如果传了就用传入的队列.如果不传,就线程池就去创建)

  • threadFactory - 执行程序创建新线程时使用的工厂

  • handler -任务执行被拒绝时使用的处理程序,因为达到线程限制和队列容量

任务执行被拒绝时使用的程序有以下四个:

在这里插入图片描述

实际开发中,主要根据需求选择这里的拒绝策略进行处理.

7. 线程池的线程数量,如何确定?

线程池可以自定义线程的数量

那么在实际开发中,线程池的线程数量设置成多少比较合适?

这个问题主要取决于以下几点:

  1. 任务类型:不同类型的任务对线程数量的需求不同。如果是CPU密集型任务,通常线程数量应该与CPU核心数相近,以充分利用CPU资源。如果是IO密集型任务,可以设置较多的线程数量,以便处理并发的IO操作。
  2. 系统资源:需要考虑系统的硬件资源和性能。如果系统资源有限,例如内存、CPU等,线程数量应适当控制,避免过多的线程导致资源竞争和性能下降。
  3. 并发量:需要根据任务的并发量来确定线程数量。如果任务并发量较高,可以增加线程数量以提高任务处理能力。如果任务并发量较低,可以减少线程数量以节省资源。
  4. 响应时间:需要考虑任务的响应时间要求。如果任务需要快速响应,可以增加线程数量以减少等待时间。如果任务的响应时间可以接受较长的延迟,可以减少线程数量以节省资源。
  5. 线程池类型:不同类型的线程池有不同的线程数量限制。例如,FixedThreadPool固定线程池的线程数量是固定的,CachedThreadPool可缓存线程池的线程数量是动态调整的。

这个问题要考虑的因素有很多,最简单的方法就是去测试

将线程分为设置成不同的数量,然后观察系统的性能和任务的执行情况,根据需要逐步调整线程数量,找到最优的配置。

在这里插入图片描述

感谢你的观看!希望这篇文章能帮到你!
专栏: 《从零开始的Java学习之旅》在不断更新中,欢迎订阅!
“愿与君共勉,携手共进!”
在这里插入图片描述

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

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

相关文章

二叉树遍历方法——前、中、后序遍历(java)

二叉树结构&#xff1a; static class TreeNode{public char val;public TreeNode left;public TreeNode right;public TreeNode(char val) {this.val val;}Overridepublic String toString() {return this.val"";}} 一、前序遍历 前序遍历是一种访问二叉树的每一…

【shell脚本】沐风晓月跟你聊聊shell脚本中的case实战

前言 前面我们已经介绍了while及for循环&#xff0c;结合if语句可以构建一些简单的控制面板及菜单脚本&#xff0c;今天我们来探讨下case语句。 case选择语句&#xff0c;主要用于对多个选择条件进行匹配输出&#xff0c;与if elif语句结构类似&#xff0c;通常用于脚本传递输…

阵列模式合成第 I 部分:清零、窗口化和细化(附源码)

一、前言 本示例说明如何使用相控阵系统工具箱解决一些阵列合成问题。在相控阵设计应用中&#xff0c;通常需要找到一种方法来逐渐减小晶片响应&#xff0c;以使最终的阵列阵列模式满足某些性能标准。典型的性能标准包括主瓣位置、零位置和旁瓣电平。 二、使用旁瓣消除器消除干…

两个进程定时通过共享内存进行通信

进程1-client #include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> #include <unistd.h> #include <string.h>#define SHM_SIZE 10 * 1024 * 1024 // 共享内存大小为10M #define WRITE_INTERVAL 1 …

PHP 基础知识

目录 PHP基础 2 PHP代码标记 2 PHP注释 2 PHP语句分隔符 2 PHP变量 3 常量 3 数据类型 4 流程控制 6 文件 7 函数 9 闭包 11 常用系统函数 12 错误处理 13 错误显示设置 15 字符串类型 17 字符串相关函数 19 数组 21 遍历数组 22 数组的相关函数 25 PHP基础 PHP是一种运行在服务…

通过netty源码带你一步步剖析NioEventLoop 的任务队列原理

NioEventLoop 的异步任务队列成员: NioEventLoop 中对newTaskQueue 接口的实现,返回的是JCTools工具包Mpsc队列(多生产者单一消费者无锁队列,(无界和有界都有实现) private static Queue<Runnable> newTaskQueue0(int maxPendingTasks) {// newMpscQueue 无界对列,newM…

10万元存款是年轻人的一个“坎”?存款超过10万就会超过53.7%的人?不要焦虑,以过来人的身份帮你分析分析!

&#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Micro麦可乐的博客 &#x1f425;《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程&#xff0c;入门到实战 &#x1f33a;《RabbitMQ》…

ChatGPT最新版实现多样化聚合文章的批量生成文章

随着人工智能技术的不断发展&#xff0c;ChatGPT最新版在多样化聚合文章的批量生成方面取得了重要突破。本文将从随机选取的8个方面&#xff0c;对ChatGPT最新版的构建思想进行详细阐述。这些方面包括&#xff1a;自然语言处理、大规模数据集、迁移学习、多模态输入、生成模型优…

JS将图片转pdf,jspdf的使用

Hi I’m Shendi 最近做转换工具&#xff0c;需要将图片转pdf&#xff0c;这里记录下来 JS将图片转pdf&#xff0c;jspdf的使用 简介 A library to generate PDFs in JavaScript. 一个用JavaScript生成PDF的库。 下载 在网站或github下载 https://parall.ax/products/jspdf …

图像增强之图像锐化(边缘增强)之sobel算子

note matx (-1,0,1;-2,0,2;-1,0,1) maty (-1,-2,-1;0,0,0;1,2,1) code // 图像增强之图像锐化(边缘增强)之sobel算子 void GetSobelMat(Mat& sobelX, Mat& sobelY) {sobelX (Mat_<int>(3,3) << -1,0,1,-2,0,2,-1,0,1);sobelY (Mat_<int>(3,3…

【面试】数据仓库

数据分层 维度建模 (0) 什么是维度建模&#xff1f; 维度建模以分析决策的需求出发构建模型&#xff0c;构建的数据模型为分析需求&#xff08;也就是我们通常所说的数据分析&#xff09;服务。它重点解决如何更快速完成分析需求&#xff0c;同时还有较好的大规模复杂查询的响…

品达通用权限系统-Day01

文章目录 1. 项目概述1.1 项目介绍1.2 业务架构1.3 技术架构1.4 环境要求 2. Spring Boot starter2.1 starter介绍2.2 starter原理2.2.1 起步依赖2.2.2 自动配置2.2.2.1 基于Java代码的Bean配置2.2.2.2 自动配置条件依赖2.2.2.3 Bean参数获取2.2.2.4 Bean的发现2.2.2.5 Bean的加…

NXP i.MX 8M Plus工业开发板规格书(四核ARM Cortex-A53 + 单核ARM Cortex-M7,主频1.6GHz)

1 评估板简介 创龙科技TLIMX8MP-EVM是一款基于NXP i.MX 8M Plus的四核ARM Cortex-A53 单核ARM Cortex-M7异构多核处理器设计的高性能工业评估板&#xff0c;由核心板和评估底板组成。ARM Cortex-A53(64-bit)主处理单元主频高达1.6GHz&#xff0c;ARM Cortex-M7实时处理单元主…

【Java】如何在 Java 中使用条件运算符

本文仅供学习参考&#xff01; 相关教程地址&#xff1a; http://c.biancheng.net/view/792.html https://www.cnblogs.com/bmbm/archive/2012/01/16/2342239.html 在软件开发中&#xff0c;运算符处理表达式中的一个或多个操作数。Java 编程语言支持以下类型的运算符&#xff…

HTML5、JS实现元素拖拽排序

先介绍一下html5的drag属性,拖放&#xff08;Drag 和 drop&#xff09;是 HTML5 标准的组成部分。想要启用drag&#xff0c;只要给元素加上draggable"true"就行了&#xff08;Safari 5.1.2除外&#xff09;。 拖动事件 事件分为两类&#xff0c;当前拖动的元素上的事…

【Makefile】解析Makefile:驾驭自动编译的力量

Makefile简介 一个工程中的源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;makefile定义了一系列的规则来指定&#xff0c;哪些文件需要先编译&#xff0c;哪些文件需要后编译&#xff0c;哪些文件需要重新编译&#xff0c;甚至于进行更复杂的…

你如何理解 JS 的继承?

在JavaScript中&#xff0c;继承是一种机制&#xff0c;允许一个对象&#xff08;子类&#xff09;从另一个对象&#xff08;父类&#xff09;继承属性和方法。这使得子类可以共享父类的功能&#xff0c;并有能∧自身定义新的功能。 JavaScript中的继承通过原型链实现。 具体来…

JavaWeb开发(前端Web开发)

文章目录 前言一、初识Web1.Web开发-介绍2.初识Web前端3.Web标准 二、HTML1.HTML快速入门2.VS Code开发工具3.基础标签&样式4.表格标签5.表单标签 三、JavaScript1.JS-介绍2.JS-引入方式3.JS-基础语法3.1.JS-基础语法-书写语法3.2.JS-基础语法-变量3.2.JS-基础语法-数据类型…

面向Java开发者的ChatGPT提示词工程(7)

在如今信息爆炸的时代&#xff0c;我们面临着海量的文字信息&#xff0c;很难抽出足够的时间去阅读所有感兴趣的内容。然而&#xff0c;大语言模型为我们提供了一种有效的解决方案&#xff1a;通过自动文本摘要&#xff0c;帮助我们快速获取文章的核心内容。这种技术已经被广泛…

vue2 h5开发前进刷新后退缓存实现

vue2 h5开发前进刷新后退缓存实现 在store定义变量 const state {includedComponents: [] }const mutations {includedComponents (state, data) {state.includedComponents data} }在app.vue&#xff08;我这里主要在layout.vue修改&#xff09;使用 keep-alive :include…