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

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

文章目录

    • 引言-购票系统
    • 线程池
      • 购票系统-线程池优化
    • 池化 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.lryc.cn/news/535131.html

相关文章:

  • WebSocket 握手过程
  • VMware 虚拟机 ubuntu 20.04 扩容工作硬盘
  • 备战蓝桥杯:二分算法之牛可乐和魔法封印问题
  • 普通用户授权docker使用权限
  • 【实战篇】DeepSeek + ElevenLabs:让人工智能“开口说话”,打造你的专属语音助手!
  • Vision Transformer:打破CNN垄断,全局注意力机制重塑计算机视觉范式
  • LabVIEW国内外开发的区别
  • 【并发控制、更新、版本控制】.NET开源ORM框架 SqlSugar 系列
  • 淘宝App交易链路终端混合场景体验探索
  • 数据中心网络监控
  • 【含开题报告+文档+PPT+源码】基于springboot的汽车销售管理系统的设计与实现
  • flink cdc2.2.1同步postgresql表
  • rebase和merge
  • Spring boot中实现字典管理
  • 调用DeepSeek官方的API接口
  • 3.3 学习UVM中的uvm_driver 类分为几步?
  • Python——批量图片转PDF(GUI版本)
  • 科技查新过不了怎么办
  • WPS中如何批量上下居中对齐word表格中的所有文字
  • 【Docker】从瀑布开发到敏捷开发
  • 若依框架二次开发——若依介绍、环境部署及更换项目包路径
  • 【DeepSeek】在本地计算机上部署DeepSeek-R1大模型实战(完整版)
  • 996引擎-问题处理:三职业改单职业
  • Redis 发生宕机时,数据怎样恢复?
  • 【02】RUST项目(Cargo)
  • 二、通义灵码插件保姆级教学-IDEA(使用篇)
  • Docker使用指南与Dockerfile文件详解:从入门到实战
  • 前端权限控制和管理
  • 网络安全讲座之一:网络安全的重要性
  • iOS主要知识点梳理回顾-3-运行时消息机制