线程池-抢票系统性能优化

文章目录

    • 引言-购票系统
    • 线程池
      • 购票系统-线程池优化
    • 池化 vs 未池化

引言-购票系统

public class App implements Runnable {private static int tickets = 100;private static int users = 10000;private final ReentrantLock lock = new ReentrantLock(true);public void run() {try {lock.lock();reduceTickets(); // 减票} finally {lock.unlock();}}private void reduceTickets() {if (tickets <= 0) return;System.out.println(Thread.currentThread().getName() + "抢到第" + tickets-- + "票");}private static void initTask(){App task = new App();Thread[] threads = new Thread[users];for (int i = 0; i < users; i++) {threads[i] = new Thread(task, "用户" + i);threads[i].start();}// 等待所有线程执行完毕for (Thread thread : threads) {try {thread.join();   // 让主线程等待该子线程执行完成后再继续} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {long startTime = System.currentTimeMillis();// 初始化任务initTask();long endTime = System.currentTimeMillis();System.out.println("程序执行时间: " + (endTime - startTime) + " 毫秒");}
}

在前面,我们通过创建多个线程模拟抢票场景,并且使用加锁的方式解决了车票超卖的问题。

每次创建一个线程,都需要执行如下步骤:

  1. 手动创建一个线程对象
  2. 执行任务
  3. 执行完毕,释放线程对象

‼️当用户量较大时,就需要频繁的创建线程对象、释放线程对象,十分麻烦。

解决方案,则是引入线程池

  1. 线程复用:在线程池中初始化指定数量的核心线程数,用户需要时直接使用线程,不需要重新创建一个新的线程对象,实现对象的复用。
  2. 线程回收:执行完任务之后,线程不会销毁,而是放回线程池中继续等待使用。
  3. 提高系统的响应速度,线程的利用率。

线程池

Java线程池是一种用于优化线程使用和管理的工具,它通过复用一定数量的线程来执行多个任务,从而减少了创建和销毁线程的开销,提高了程序的性能和响应速度。

Java中的线程池是通过java.util.concurrent包下的Executor接口及其子类来实现的。

以下是一些关键的类和接口,用于在Java中创建和使用线程池:

  1. Executor接口:这是一个基础接口,用于执行提交的任务。
  2. ExecutorService接口:扩展了Executor接口,添加了用于管理执行器生命周期的方法,如关闭线程池。
  3. ThreadPoolExecutor类:是ExecutorService的一个实现,它允许更详细地配置线程池。
  4. Executors类:提供了创建线程池的工厂方法。

以下是几种常见的线程池类型,可以通过Executors类来创建:

  1. FixedThreadPool:固定数量的线程池,适用于负载比较重的服务器。
  2. SingleThreadExecutor:只有一个线程的线程池,适用于需要保证顺序执行的场景。
  3. CachedThreadPool:根据需要创建新线程的线程池,适用于执行很多短期异步任务的程序。
  4. ScheduledThreadPool:用于执行定时任务或周期性任务。

购票系统-线程池优化

  1. 初始化:线程池将根据预设配置初始化一定数量的核心线程。
  2. 新增线程:当任务提交量超过核心线程数时,系统会按需创建额外的工作线程以处理新增的任务负载。
  3. 最大线程数:若当前活跃的线程数目已达到设定的最大值,新到达的任务会被安排进入等待队列中暂存。
  4. 拒绝策略:在等待队列也达到了其容量上限的情况下,对于后续继续提交的新任务,线程池将依据预定义的拒绝策略进行处理,即不再接受新的任务请求。
public class ThreadPool implements Runnable {private static int tickets = 100;private static int users = 200000;private final ReentrantLock lock = new ReentrantLock(true);public void run() {try {lock.lock();reduceTickets(); // 减票} finally {lock.unlock();}}private void reduceTickets() {if (tickets <= 0) return;System.out.println(Thread.currentThread().getName() + "抢到第" + tickets-- + "票");}private static void initTask(){// 创建线程池ExecutorService pool = new ThreadPoolExecutor(5,    // 核心线程数16,   // 最大线程数0L, TimeUnit.MILLISECONDS,  // 线程空闲时间new LinkedBlockingQueue<Runnable>() // 任务队列);// 创建任务ThreadPool task = new ThreadPool();for (int i = 0; i < users; i++) {pool.submit(new Thread(task, "用户" + i));}// 执行完毕,关闭线程池pool.shutdown();try {// 等待所有线程执行完毕if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {pool.shutdownNow(); // 超时强制关闭}} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args) {long startTime = System.currentTimeMillis();// 初始化任务initTask();long endTime = System.currentTimeMillis();System.out.println("程序执行时间: " + (endTime - startTime) + " 毫秒");}
}

池化 vs 未池化

  1. 电脑核心线程数( NumberOfCores ) = 12,逻辑核心数 = 16
  2. 票数 = 100,用户数量 = 10000,模拟 10000 个用户同事抢 100 张票。
****核心线程数最大线程数执行时间
未池化18832 ms
线程池配置 05854 ms
线程池配置 151056 ms
线程池配置 251627 ms

池化后,性能得到了质的飞跃🚀。

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

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

相关文章

【多模态大模型】系列1:Transformer Encoder——ViLT、ALBEF、VLMO

目录 1 ViLT2 ALBEF3 VLMO 1 ViLT ViLT: Vision-and-Language Transformer Without Convolution or Region Supervision 图文多模态任务&#xff0c;关键是提取视觉特征和文本特征&#xff0c;然后对齐。在之前的多模态研究工作中&#xff0c;视觉侧通常需要一个目标检测器来…

百度 API 教程 001:显示地图并添加控件

目录 01、基本使用 前期准备 显示地图 开启鼠标滚轮缩放地图 02、添加地图控件 添加标准地图控件 添加多个控件 网址&#xff1a;地图 JS API | 百度地图API SDK 01、基本使用 前期准备 注册百度账号 申请成为开发者 获取密钥&#xff1a;控制台 | 百度地图开放平台…

电容器教程摘要

正如我们将在本电容器教程中看到的那样&#xff0c;电容器是能够在其板上存储电荷的能源。因此&#xff0c;电容器由于存储充电的能力而存储能量&#xff0c;理想的电容器不会松散其存储的能量。 电容器的简单结构是使用两个平行的导电金属板通过绝缘材料通过距离分开。这种绝…

【通俗易懂说模型】一篇弄懂几个经典CNN图像模型(AlexNet、VGGNet、ResNet)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;深度学习_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前言 2. …

【EXCEL】【VBA】处理GI Log获得Surf格式的CONTOUR DATA

【EXCEL】【VBA】处理GI Log获得Surf格式的CONTOUR DATA data source1: BH coordination tabledata source2:BH layer tableprocess 1:Collect BH List To Layer Tableprocess 2:match Reduced Level from "Layer"+"BH"data source1: BH coordination…

汇编简介常用语法

为什么要有汇编 因为Cortex-A芯片一上电SP指针还没初始化&#xff0c;C环境还没准备 好&#xff0c;所以肯定不能运行C代码&#xff0c;必须先用汇编语言设置好C环境&#xff0c;比如初始化DDR、设置SP 指针等等&#xff0c;当汇编把C环境设置好了以后才可以运行C代码 GNU语法…

内网ip网段记录

1.介绍 常见的内网IP段有&#xff1a; A类&#xff1a; 10.0.0.0/8 大型企业内部网络&#xff08;如 AWS、阿里云&#xff09; 10.0.0.0 - 10.255.255.255 B类&#xff1a;172.16.0.0/12 中型企业、学校 172.16.0.0 - 172.31.255.255 C类&#xff1a;192.168.0.0/16 家庭…

ComfyUI流程图生图原理详解

一、引言 ComfyUI 是一款功能强大的工具&#xff0c;在图像生成等领域有着广泛应用。本文补充一点ComfyUI 的安装与配置过程遇到的问题&#xff0c;并深入剖析图生图过程及相关参数&#xff0c;帮助读者快速入门并深入理解其原理。 二、ComfyUI 的安装与配置中遇到的问题 &a…

无人机遥感图像拼接及处理实践技术:生态环境监测、农业、林业等领域,结合图像拼接与处理技术,能够帮助我们更高效地进行地表空间要素的动态监测与分析

近年来&#xff0c;无人机技术在遥感领域的应用越来越广泛&#xff0c;尤其是在生态环境监测、农业、林业等领域&#xff0c;无人机遥感图像的处理与分析成为了科研和业务化工作中的重要环节。通过无人机获取的高分辨率影像数据&#xff0c;结合图像拼接与处理技术&#xff0c;…

web渗透测试之反弹shell SSRF结合redis结合伪协议 redis 未授权访问漏洞

目录 未授权访问漏洞利用:redis 反弹shell 漏洞原因就是&#xff1a; 反弹shell利用方式 反弹shell指的是什么 : 反弹shell的前提条件 步骤: redis未授权访问的三种利用手段反弹shell 利用定时任务反弹shell 攻击主机下设置 写入 webshell 步骤 利用公钥认证写入ro…

【Vue】打包vue3+vite项目发布到github page的完整过程

文章目录 第一步&#xff1a;打包第二步&#xff1a;github仓库设置第三步&#xff1a;安装插件gh-pages第四步&#xff1a;两个配置第五步&#xff1a;上传github其他问题1. 路由2.待补充 参考文章&#xff1a; 环境&#xff1a; vue3vite windows11&#xff08;使用终端即可&…

Win32/C++ 字符串操作实用工具

CStrUtils.h #pragma once#include <string> #include <vector> #include <windows.h> #include <tchar.h>#ifdef _UNICODE using _tstring std::wstring; #else using _tstring std::string; #endif// 字符串转换实用工具 namespace CStrUtils {//…

【C++前缀和】1074. 元素和为目标值的子矩阵数量|2189

本文涉及的基础知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 LeetCode1074. 元素和为目标值的子矩阵数量 给出矩阵 matrix 和目标值 target&#xff0c;返回元素总和等于目标值的非空子矩阵的数量。 子矩阵 x1, y1, x2, y2 是满…

【安当产品应用案例100集】037-强化OpenVPN安全防线的卓越之选——安当ASP身份认证系统

在当前数字化时代&#xff0c;网络安全已成为企业发展的重要组成部分。对于使用OpenVPN的企业而言&#xff0c;确保远程访问的安全性尤为重要。安当ASP身份认证系统凭借其强大的功能和便捷的集成方式&#xff0c;为OpenVPN的二次登录认证提供了理想的解决方案&#xff0c;特别是…

基于进化式大语言模型的下一代漏洞挖掘范式:智能对抗与自适应攻防体系

摘要 本文提出了一种基于进化式大语言模型(Evolutionary LLM)的智能漏洞挖掘框架,突破了传统静态分析的局限,构建了具备对抗性思维的动态攻防体系。通过引入深度强化学习与多模态感知机制,实现了漏洞挖掘过程的自适应进化,在RCE、SQLi、XXE等关键漏洞类型的检测中达到97…

2025年数据资产管理解决方案:资料合集,从基础知识到行业应用的全面解析

在数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。如何有效地管理和利用这些数据&#xff0c;将其转化为实际的经济价值&#xff0c;已成为企业面临的重要课题。 本文将通过数据资产解决方案、数据资产行业报告白皮书、数据资产政策汇编、数据资产基础知识以及数据资…

【linux学习指南】模拟线程封装与智能指针shared_ptr

文章目录 &#x1f4dd;线程封装&#x1f309; Thread.hpp&#x1f309; Makefile &#x1f320;线程封装第一版&#x1f309; Makefile:&#x1f309;Main.cc&#x1f309; Thread.hpp: &#x1f320;线程封装第二版&#x1f309; Thread.hpp:&#x1f309; Main.cc &#x1f…

k8s的安装

1. k8s的安装 192.168.48.6 master01 192.168.481.6 node01 192.168.48.26 node02 三台机器一起操作 1.swapoff -a &#xff1a;关闭交换分区 2. iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X 3. cat > /etc/sy…

字节跳动大模型应用 Go 开发框架 —— Eino 实践

前言 开发基于大模型的软件应用&#xff0c;就像指挥一支足球队&#xff1a;组件是能力各异的队员&#xff0c;编排是灵活多变的战术&#xff0c;数据是流转的足球。Eino 是字节跳动开源的大模型应用开发框架&#xff0c;拥有稳定的内核&#xff0c;灵活的扩展性&#xff0c;完…

redis之数据库

文章目录 服务器中的数据库切换数据库数据库键空间读写键空间时的维护操作 设置键的生存时间或过期时间保存过期时间过期键的判定过期键删除策略清性删除策略的实现定期删除策略的实现 总结 服务器中的数据库 Redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结…