当前位置: 首页 > news >正文

深入理解高并发编程 - 分析创建线程池究竟有哪些方式

1、使用Executors工厂方法:

使用Executors工厂方法创建线程池是一种简单快捷的方式,适用于一些常见的线程池需求。以下是几个示例,演示如何使用Executors工厂方法创建不同类型的线程池:

固定大小线程池 (newFixedThreadPool):

这种类型的线程池会一直保持固定数量的线程在池中,不会自动回收线程。适用于需要限制同时执行的任务数量的场景。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class FixedThreadPoolExample {public static void main(String[] args) {int numThreads = 5;ExecutorService executor = Executors.newFixedThreadPool(numThreads);// 提交任务到线程池for (int i = 0; i < 10; i++) {executor.submit(new MyRunnable(i));}executor.shutdown(); // 关闭线程池}
}

缓存线程池 (newCachedThreadPool):

缓存线程池会根据需要创建新的线程,如果线程池中的线程空闲时间超过指定的时间,则会被回收。适用于任务数量不确定,且需要自动调整线程数的场景。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class CachedThreadPoolExample {public static void main(String[] args) {ExecutorService executor = Executors.newCachedThreadPool();// 提交任务到线程池for (int i = 0; i < 10; i++) {executor.submit(new MyRunnable(i));}executor.shutdown(); // 关闭线程池}
}

单线程线程池 (newSingleThreadExecutor):

单线程线程池只有一个工作线程,适用于需要按顺序执行任务的场景。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class SingleThreadExecutorExample {public static void main(String[] args) {ExecutorService executor = Executors.newSingleThreadExecutor();// 提交任务到线程池for (int i = 0; i < 10; i++) {executor.submit(new MyRunnable(i));}executor.shutdown(); // 关闭线程池}
}

定时任务线程池 (newScheduledThreadPool):

定时任务线程池用于执行定时任务和周期性任务。

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;public class ScheduledThreadPoolExample {public static void main(String[] args) {int numThreads = 3;ScheduledExecutorService executor = Executors.newScheduledThreadPool(numThreads);// 延迟1秒后执行任务executor.schedule(new MyRunnable(1), 1, TimeUnit.SECONDS);// 延迟2秒后,每3秒执行一次任务executor.scheduleAtFixedRate(new MyRunnable(2), 2, 3, TimeUnit.SECONDS);// 关闭线程池executor.shutdown();}
}

在这些示例中,MyRunnable是一个实现了Runnable接口的自定义任务类。创建线程池后,使用submit方法将任务提交给线程池进行执行,并最终调用shutdown方法关闭线程池。

这些Executors工厂方法提供了一些常见的线程池类型,但在某些情况下,可能需要更精细的线程池配置,这时可以考虑手动创建ThreadPoolExecutor。

2、手动创建ThreadPoolExecutor:

手动创建 ThreadPoolExecutor 允许对线程池的各种参数进行更精细的配置,以满足特定的需求。以下是一个示例,演示如何手动创建 ThreadPoolExecutor:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class ManualThreadPoolExecutorExample {public static void main(String[] args) {int corePoolSize = 5;int maxPoolSize = 10;long keepAliveTime = 60; // 60秒TimeUnit timeUnit = TimeUnit.SECONDS;BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, timeUnit, workQueue);// 提交任务到线程池for (int i = 0; i < 10; i++) {executor.submit(new MyRunnable(i));}executor.shutdown(); // 关闭线程池}
}class MyRunnable implements Runnable {private int id;public MyRunnable(int id) {this.id = id;}@Overridepublic void run() {System.out.println("Task " + id + " is running on thread " + Thread.currentThread().getName());}
}

在这个示例中,手动创建了一个 ThreadPoolExecutor,并配置了核心线程数、最大线程数、线程空闲时间等参数。然后,使用 submit 方法将任务提交给线程池进行执行,并最终调用 shutdown 方法关闭线程池。

注意,BlockingQueue 参数用于指定任务队列,用来存储等待执行的任务。在这里,使用了 LinkedBlockingQueue,也可以选择其他的实现,如 ArrayBlockingQueue、PriorityBlockingQueue 等,以适应不同的需求。

手动创建 ThreadPoolExecutor 允许更精细地控制线程池的行为,但也需要更多的配置和管理。在选择线程池类型和参数时,应根据应用的特性和需求进行调整。

3、使用ForkJoinPool:

ForkJoinPool 是 Java 提供的用于支持分治任务的线程池实现。它特别适用于能够将任务拆分成更小的子任务,并且这些子任务可以并行执行的情况。以下是一个使用 ForkJoinPool 创建线程池的示例:

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;public class ForkJoinPoolExample {public static void main(String[] args) {ForkJoinPool forkJoinPool = new ForkJoinPool();MyRecursiveAction task = new MyRecursiveAction(0, 10);forkJoinPool.invoke(task);forkJoinPool.shutdown();}
}class MyRecursiveAction extends RecursiveAction {private static final int THRESHOLD = 2; // 阈值,小于该值就不再分解任务private int start;private int end;public MyRecursiveAction(int start, int end) {this.start = start;this.end = end;}@Overrideprotected void compute() {if (end - start <= THRESHOLD) {// 执行任务逻辑for (int i = start; i <= end; i++) {System.out.println("Task is running on thread " + Thread.currentThread().getName() + ": " + i);}} else {// 分解任务int mid = (start + end) / 2;MyRecursiveAction left = new MyRecursiveAction(start, mid);MyRecursiveAction right = new MyRecursiveAction(mid + 1, end);invokeAll(left, right);}}
}

在这个示例中,首先创建了一个 ForkJoinPool 实例,然后定义了一个继承自 RecursiveAction 的 MyRecursiveAction 类,用于表示要执行的分治任务。在 compute 方法中,首先检查任务是否足够小,如果是,则执行任务逻辑;否则,将任务分解为两个子任务并使用 invokeAll 方法并行执行。

ForkJoinPool 会根据任务的大小和可用线程数来动态地调度任务的执行,以获得最佳的并行性能。在实际使用中,可以根据任务的特性和复杂度调整阈值,以及分解和执行子任务的逻辑。

注意,ForkJoinPool 适用于能够利用分治并行计算的场景,如递归问题的解决和并行计算任务。

4、使用 ScheduledThreadPoolExecutor 类

ScheduledThreadPoolExecutor 是 ThreadPoolExecutor 的子类,专门用于创建带有定时任务功能的线程池。它可以执行定时任务和周期性任务。以下是一个使用 ScheduledThreadPoolExecutor 创建线程池的示例:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;public class ScheduledThreadPoolExecutorExample {public static void main(String[] args) {int numThreads = 3;ScheduledExecutorService executor = Executors.newScheduledThreadPool(numThreads);// 延迟1秒后执行任务executor.schedule(new MyRunnable(1), 1, TimeUnit.SECONDS);// 延迟2秒后,每3秒执行一次任务executor.scheduleAtFixedRate(new MyRunnable(2), 2, 3, TimeUnit.SECONDS);// 关闭线程池executor.shutdown();}
}class MyRunnable implements Runnable {private int id;public MyRunnable(int id) {this.id = id;}@Overridepublic void run() {System.out.println("Task " + id + " is running on thread " + Thread.currentThread().getName());}
}

在这个示例中,使用 Executors.newScheduledThreadPool() 方法创建了一个 ScheduledExecutorService,然后使用 schedule 方法在指定的延迟时间后执行一次任务,使用 scheduleAtFixedRate 方法在指定的延迟时间后开始执行任务,并且每隔一段时间重复执行。

ScheduledThreadPoolExecutor 可以满足定时任务和周期性任务的需求,它能够自动调度任务的执行。当任务执行时间超过任务间隔时间时,ScheduledThreadPoolExecutor 会等待当前任务完成后再启动下一个任务。这种特性对于需要保证任务执行间隔的场景非常有用。

5、使用第三方库(如ThreadPoolExecutor的封装库):

许多第三方库都提供了对 ThreadPoolExecutor 的封装,以便更方便地创建和管理线程池。其中一个常用的库是 Apache Commons Lang 中的 ThreadPoolExecutor,它提供了一些额外的功能和配置选项。以下是一个使用 Apache Commons Lang 的 ThreadPoolExecutor 封装库的示例:

首先,确保已经将 Apache Commons Lang 库添加到项目中。然后,你可以使用 org.apache.commons.lang3.concurrent.BasicThreadFactory 来创建线程池。下面是示例代码:

import org.apache.commons.lang3.concurrent.BasicThreadFactory;import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class ThirdPartyThreadPoolExample {public static void main(String[] args) {int numThreads = 3;BasicThreadFactory factory = new BasicThreadFactory.Builder().namingPattern("my-pool-%d").daemon(true).build();ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(numThreads, factory);// 延迟1秒后执行任务executor.schedule(new MyRunnable(1), 1, TimeUnit.SECONDS);// 延迟2秒后,每3秒执行一次任务executor.scheduleAtFixedRate(new MyRunnable(2), 2, 3, TimeUnit.SECONDS);// 关闭线程池executor.shutdown();}
}class MyRunnable implements Runnable {private int id;public MyRunnable(int id) {this.id = id;}@Overridepublic void run() {System.out.println("Task " + id + " is running on thread " + Thread.currentThread().getName());}
}

在这个示例中,使用 BasicThreadFactory 来配置线程池。通过设置不同的属性,可以定制线程名、守护线程属性等。然后,使用 ScheduledThreadPoolExecutor 创建一个带有定时任务功能的线程池,并使用 schedule 和 scheduleAtFixedRate 方法添加定时任务。

使用第三方库的线程池封装可以帮助更方便地创建和管理线程池,以及提供一些额外的功能选项。

相关文章:

深入理解高并发编程 - 分析创建线程池究竟有哪些方式

1、使用Executors工厂方法&#xff1a; 使用Executors工厂方法创建线程池是一种简单快捷的方式&#xff0c;适用于一些常见的线程池需求。以下是几个示例&#xff0c;演示如何使用Executors工厂方法创建不同类型的线程池&#xff1a; 固定大小线程池 (newFixedThreadPool)&am…...

Kafka第一课概述与安装

生产经验 面试重点 Broker面试重点 代码,开发重点 67 章了解 如何记录行为数据 1. Kafka概述 1.产生原因 前端 传到日志 日志传到Flume 传到HADOOP 但是如果数据特比大&#xff0c;HADOOP就承受不住了 2.Kafka解决问题 控流消峰 Flume传给Kafka 存到Kafka Hadoop 从Kafka…...

Linux MQTT智能家居项目(智能家居界面布局)

文章目录 前言一、创建工程项目二、界面布局准备工作三、正式界面布局总结 前言 一、创建工程项目 1.选择工程名称和项目保存路径 2.选择QWidget 3.添加保存图片的资源文件&#xff1a; 在工程目录下添加Icon文件夹保存图片&#xff1a; 将文件放入目录中&#xff1a; …...

【Vue3】Vue3 UI 框架 | Element Plus —— 创建并优化表单

安装 # NPM $ npm install element-plus --save // 或者&#xff08;下载慢切换国内镜像&#xff09; $ npm install element-plus -S// 可以选择性安装 less npm install less less-loader -D // 可以选择性配置 自动联想src目录Element Plus 的引入和注入 main.ts import…...

如何基于 ACK Serverless 快速部署 AI 推理服务

作者&#xff1a;元毅 随着 AI 浪潮的到来&#xff0c;各种 AI 应用层出不穷&#xff0c;众所周知 AI 应用对 GPU 资源强烈依赖&#xff0c;但 GPU 很昂贵&#xff0c;如何降低 GPU 资源使用成本成为用户首要问题。而 AI 与 Serverless 技术结合&#xff0c;完全可以达到按需使…...

【奥义】如何用ChatGPT写论文搞模型

目录 你是否曾经在复现科研论文的结果时感到困难重重&#xff1f; 引言 1 打开需要复现的目标文献 2 提取公式定义的语句 3 文章公式、图实现 &#xff08;1&#xff09;用python复现目标文献中的公式 &#xff08;2&#xff09;用python复现目标文献中的图 4 Copy代码…...

欢迎光临,博客网站

欢迎光临&#xff1a;YUNYE博客~https://yunyeblog.com/更多的文章&#xff0c;供大家参考学习&#xff01;&#xff01;&#xff01;...

通过TightVNC远程访问MacOS

目录 一、下载 TightVNC 下载链接&#xff1a;https://www.tightvnc.com/ 下载后按步骤进行安装&#xff0c;安装完成后安装目录如下&#xff1a; 运行 tvnviewer.exe&#xff0c;输入远程 IP&#xff0c;点击【connect】&#xff1a; 输入密码&#xff0c;点击【OK】后即可远…...

智安网络|网络安全:危机下的创新与合作

随着信息技术的迅猛发展和互联网的普及&#xff0c;我们进入了一个高度网络化的社会。网络在提供便利和连接的同时&#xff0c;也带来了许多安全隐患和挑战。 一、网络安全的危险 **1.数据泄露和隐私侵犯&#xff1a;**网络上的个人和机构数据存在遭受泄露和盗取的风险&#…...

从系统角度,看智能制造|百世慧®

7月31日我们结束了智能制造专题第二期“电池智能制造质量管理应用及案例分享”的线上研讨会&#xff0c;有不少朋友没有来得及参加智能制造专题第一期研讨会&#xff0c;同时又工作繁忙。所以&#xff01;今天就由我百小能为大家快速讲解第一期研讨会——“电池智能制造应用”的…...

Dubbo 与 gRPC、Spring Cloud、Istio 的关系

很多开发者经常会问到 Apache Dubbo 与 Spring Cloud、gRPC 以及一些 Service Mesh 项目如 Istio 的关系&#xff0c;要解释清楚它们的关系并不困难&#xff0c;你只需要跟随这篇文章和 Dubbo 文档做一些更深入的了解&#xff0c;但总的来说&#xff0c;它们之间有些能力是重合…...

【uniapp 中使用uni-popup阻止左滑退出程序】

在uniapp中&#xff0c;可以使用uni-app插件uni-popup提供的阻止左滑退出程序的功能。具体步骤如下&#xff1a; 安装uni-popup插件&#xff1a;在HBuilderX编辑器中&#xff0c;打开manifest.json文件&#xff0c;找到“dependencies”字段&#xff0c;在其后添加&#xff1a…...

netty学习分享(一)

TCP与UDP TCP 是面向连接的、可靠的流协议&#xff0c;通过三次握手建立连接&#xff0c;通讯完成时要拆除连接。 UDP是面向无连接的通讯协议&#xff0c;UDP通讯时不需要接收方确认&#xff0c;属于不可靠的传输&#xff0c;可能会出现丢包现象 端口号&#xff1a; 端口号用…...

前端跨域问题解决方法

跨域是WEB浏览器专有的同源限制访问策略。(后台接口调用和postman等工具会出现) 跨源资源共享&#xff08;CORS&#xff0c;或通俗地译为跨域资源共享&#xff09;是一种基于 HTTP 头的机制&#xff0c;该机制通过允许服务器标示除了它自己以外的其他源&#xff08;域、协议或端…...

html基础面试题 html的元素居中的常用方法(基础知识温习)

html基础面试题 & html的元素居中的常用方法日常温习 1&#xff0c;使用text-align: center;属性&#xff1a; 对于内联元素&#xff08;如文本或图片&#xff09;&#xff0c;可以将其父元素的text-align属性设置为center。 <div style"text-align: center;&quo…...

VScode如何设置中文教程

前言&#xff1a;打开VSCode软件&#xff0c;可以看到刚刚安装的VSCode软件默认使用的是英文语言环境&#xff0c;但网上都是vscode中文界面教你怎么设置中文&#xff0c;可能不利于小白阅读&#xff0c;所以重装vscode&#xff0c;手摸手从英文变成中文。 设置为中文 打开VS…...

SpringCloud中 Sentinel 限流的使用

引入依赖 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>手动编写限流规则&#xff0c;缺点是不够灵活&#xff0c;如果需要改变限流规则需要修改源码…...

springboot文件上传和下载接口的简单思路

springboot文件上传和下载的简单思路 文件上传文件下载 文件上传 在springboot中&#xff0c;上传文件只需要在接口中通过 MultipartFile 对象来获取前端传递的数据&#xff0c;然后将数据存储&#xff0c;并且返回一个对外访问路径即可。一般对于上传文件的文件名&#xff0c…...

MySQL索引和事务

目录 索引的作用 与 概念 MySQL有哪几种索引类型 如何提高查找效率 聚簇索引与非聚簇索引 覆盖索引 索引的优点和缺点 索引的一些基本操作 索引优化 B树、B树、Hash、红黑树的区别 B树与B树的区别 MySQL为什么使用B树作为索引 联合索引中的顺序 MySQL的最左前缀原…...

typeScript 之 基础

工具: PlayGround 源码&#xff1a; GitHub TypeScript 变量声明 typeScript中变量声明注意&#xff1a; 开头不能以数字开头变量名称可以包含数字和字母除了下划线_和美元$符号外&#xff0c;不能包含其他任意特殊字符 声明的结构&#xff1a; let 变量名&#xff1a; 类型…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...

Razor编程中@Html的方法使用大全

文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...

省略号和可变参数模板

本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...