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

引言-购票系统

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.线程池的工作流程

  1. 初始化:线程池将根据预设配置初始化一定数量的核心线程;
  2. 等待队列:如果**“请求线程数量”>“核心线程数”**,新增用户请求就会进入“等待队列”;
  3. 新增线程:当等待队列达到容量上限,此时会创建新的“非核心线程”处理请求;
  4. 拒绝策略:当**“等待队列”容量上限**,“线程池数量”达到预设最大数量,对于后续继续提交的新任务,线程池将依据预定义的“拒绝策略”进行处理,即不再接受新的任务请求。

2.购票系统-线程池优化

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

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

线程池的参数说明

todo。。。

线程池的工作队列

todo。。。

线程池的拒绝策略

todo。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值