自定义ThreadsExecutor线程池工具类,根据任务增加线程,解决ThreadPoolExecutor先放入队列再新增线程

43 阅读7分钟

线程池工具类,本工具存在意义:解决 java.util.concurrent.ThreadPoolExecutor 不涵盖的领域。 (在2025/01/07文末有更新,可借用 java.util.concurrent.ThreadPoolExecutor 达到了同样效果)

一、原:手搓线程池办法:

【对比如下】: 1、ThreadPoolExecutor线程池工具,核心包含:corePoolSize、maximumPoolSize、Queue。 运行逻辑:初始化时创建corePoolSize个线程,来任务用线程执行(最大corePoolSize个),再新来任务放入Queue,Queue放满后新增线程到maximumPoolSize个,...全部任务执行完保持corePoolSize个线程。 2、ThreadsExecutor(本类)线程池工具,核心包含:maximumPoolSize、namePrefix。 运行逻辑:初始化时创建0个线程,来任务则创建线程执行(最大maximumPoolSize个),再新来任务放入Queue,前面创建的线程任务执行完后从Queue取任务继续执行,全部任务执行完0个线程。

【本类优势】:不需要保持corePoolSize个线程,节约资源:保持1个线程大概耗费1M内存,以及CPU上下文切换耗费(即使线程是休眠状态)

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Queue;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.function.IntUnaryOperator;

/**
 * Description : 线程池工具类,本工具存在意义:解决 java.util.concurrent.ThreadPoolExecutor 不涵盖的领域。
 * <p>
 * 【对比如下】:
 * 1、ThreadPoolExecutor线程池工具,核心包含:corePoolSize、maximumPoolSize、Queue。
 * 运行逻辑:初始化时创建corePoolSize个线程,来任务用线程执行(最大corePoolSize个),再新来任务放入Queue,Queue放满后新增线程到maximumPoolSize个,...全部任务执行完保持corePoolSize个线程。
 * 2、ThreadsExecutor(本类)线程池工具,核心包含:maximumPoolSize、namePrefix。
 * 运行逻辑:初始化时创建0个线程,来任务则创建线程执行(最大maximumPoolSize个),再新来任务放入Queue,前面创建的线程任务执行完后从Queue取任务继续执行,全部任务执行完0个线程。
 * <p>
 * 【本类优势】:不需要保持corePoolSize个线程,节约资源:保持1个线程大概耗费1M内存,以及CPU上下文切换耗费(即使线程是休眠状态)
 *
 * @Author mr li
 * @Version v1.0
 * @create 2024/07/02 09:19
 */
public class ThreadsExecutor {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @FunctionalInterface
    public interface Process {
        void start() throws Exception;
    }

    private AtomicInteger count;
    private Queue<Process> queue;
    private int maximumPoolSize;
    private AtomicBoolean isShutdown;
    private String namePrefix;

    public ThreadsExecutor(int maximumPoolSize) {
        this.maximumPoolSize = maximumPoolSize;
        this.queue = new ConcurrentLinkedQueue<>();
        this.count = new AtomicInteger(0);
        this.isShutdown = new AtomicBoolean(false);
    }

    public ThreadsExecutor(int maximumPoolSize, String namePrefix) {
        this.maximumPoolSize = maximumPoolSize;
        this.queue = new ConcurrentLinkedQueue<>();
        this.count = new AtomicInteger(0);
        this.isShutdown = new AtomicBoolean(false);
        this.namePrefix = namePrefix;
    }

    //不会中断工作线程,也不会清空工作队列,已提交任务正常执行,但是拒绝新提交的任务。(即已提交任务不受任务影响)
    public synchronized void shutdown() {
        isShutdown.set(true);
    }

    //会中断所有工作线程,并清空工作队列,拒绝新提交的任务。
    public synchronized void shutdownNow() {
        throw new IllegalStateException("This method is temporarily not supported.");
    }

    public boolean isShutdown() {
        return isShutdown.get();
    }

    public boolean isTerminated() {
        return 0 == count.get();
    }

    public boolean isCompleted() {
        return isTerminated();
    }

    public void execute(Process process) {
        if (isShutdown.get()) {
            throw new IllegalStateException("ThreadPool is shutdown, can not execute new tasks.");
        }
        // 具体执行
//        if (count.get() < maximumPoolSize) {
//            count.incrementAndGet();
//            newThread(command).start();
//        } else {
//            queue.add(command);
//        }
        IntUnaryOperator updateFunction = currentValue -> {
            if (currentValue < maximumPoolSize) {
                return currentValue + 1; // 如果小于阈值,则加 1
            }
            return currentValue; // 否则保持不变
        };
        int oldValue = count.getAndUpdate(updateFunction); // 获取更新前的值
        if (oldValue < maximumPoolSize) {
            newThread(process).start();
        } else {
            queue.add(process);
        }
    }

    private Thread newThread(Process process) {
        Thread t = new Thread(() -> run(process));
        if (null == namePrefix || namePrefix.trim().length() == 0) {
            return t;
        }
        t.setName(namePrefix + "-" + t.getName().split("-")[1]);
        return t;
    }

    private void run(Process process) {
//        if (isShutdown.get()) {  //遵循ThreadPoolExecutor标准逻辑,shutdown()只是不接收新任务,但是不能影响已接收的任务执行
//            count.decrementAndGet();
//            return;
//        }
        if (null == process) {
            count.decrementAndGet();
            return;
        }
        boolean isException = false;
        try {
            process.start();
        } catch (Exception e) {
            isException = true;
            logger.error(e.getMessage(), e);
            throw new RuntimeException(e);
        } finally {
            // 异常线程停止,新线程去执行.
            if (isException) {
                newThread(queue.poll()).start();
            } else {
                run(queue.poll());
            }
        }
    }


    /**
     * 使用例子
     * @param args
     */
    public static void main(String[] args) throws InterruptedException {
        ThreadsExecutor executor = new ThreadsExecutor(3, "mine");
        bingfa(100, () -> {
            executor.execute(() -> {
                System.out.println("Thread: " + Thread.currentThread().getName() +" "+ Thread.currentThread().getId());
                try {
                    Thread.sleep((long) (Math.random() * 1000));// 模拟方法执行时间
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            });
        });
        System.out.println("overoveroverover");
    }

    private static void bingfa(int bingfaSize, Runnable command) throws InterruptedException {
        final int concurrencyLevel = bingfaSize; // 并发量
        ExecutorService executor = Executors.newFixedThreadPool(concurrencyLevel);
        CountDownLatch startSignal = new CountDownLatch(1); // 开始信号
        CountDownLatch endSignal = new CountDownLatch(concurrencyLevel); // 结束信号
        // 提交并发任务
        for (int i = 0; i < concurrencyLevel; i++) {
            final int txt = i;
            executor.submit(() -> {
                try {
                    startSignal.await();    // 等待开始信号
                    command.run();                    // 调用目标方法
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    endSignal.countDown();  // 标记当前任务完成
                }
            });
        }
        startSignal.countDown(); // 触发所有任务同时开始
        endSignal.await();       // 等待所有任务完成
        executor.shutdown();     // 关闭线程池
    }

}

AI代码解析(Kimi): 这段Java代码定义了一个名为 ThreadsExecutor 的线程池工具类,它提供了一种自定义的线程池实现,与 java.util.concurrent.ThreadPoolExecutor 相比,它有一些不同的特性和运行逻辑。 以下是代码的主要特点和功能:

  1. 接口定义: Process 是一个函数式接口,用于定义任务执行的方法 start()
  2. 构造函数:接受1个参数 maximumPoolSize ,表示线程池中最大线程数。接受2个参数,maximumPoolSize 表示线程池中最大线程数,namePrefix,表示线程命名前缀。
  3. 线程池属性: count :使用 AtomicInteger 来记录当前活跃线程的数量。 queue :使用 ConcurrentLinkedQueue 作为任务队列,用于存储待执行的任务。 maximumPoolSize :定义线程池的最大线程数。 isShutdown :使用 AtomicBoolean 来记录是否线程池是否关闭。 namePrefix :定义线程命名前缀。
  4. 执行方法: execute(Process process) 方法用于提交新任务。如果当前活跃线程数小于最大线程数,则创建新线程执行任务;否则,将任务添加到队列中。
  5. 线程创建:newThread(Process process) 方法是线程创建。如果 namePrefix 是否为null或空字符串,则默认命名;否则使用namePrefix 命名前缀。
  6. 任务执行: run(Process process) 方法是任务的实际执行逻辑。它尝试执行传入的任务,并在执行完毕后,根据是否有异常发生来决定是停止线程还是继续执行队列中的下一个任务。
  7. 异常处理:如果任务执行过程中发生异常,会创建新线程来执行队列中的下一个任务,而当前线程会停止。
  8. 示例: main 方法展示了如何使用 ThreadsExecutor 类。创建了一个最大线程数为3的线程池,并提交了50个任务。其中一个任务(当 x == 10 时)会抛出异常。
  9. 资源节约:与标准的 ThreadPoolExecutor 相比, ThreadsExecutor 不需要保持一定数量的核心线程,这可以节省内存和减少CPU上下文切换的开销。
  10. 线程池关闭: shutdown() 方法用于关闭线程池,阻止新来的任务提交,对已经提交了的任务不会产生任何影响,这个过程是异步的。
  11. 线程池立刻关闭: shutdownNow() 方法暂不支持。
  12. 线程池关闭检查: isShutdown() 方法用于检查线程池是否已关闭。
  13. 线程池状态检查: isTerminated() 方法用于检查所有任务是否已完成。
  14. 线程池状态检查: isCompleted() 方法同isTerminated()。 这段代码是一个自定义线程池的简单实现,适用于需要控制线程数量和任务执行顺序的场景。

二、2025/01/07更新:可借用 java.util.concurrent.ThreadPoolExecutor 达到了同样效果:

package cn.cdcyy.base.tool;

import java.util.concurrent.*;

/**
 * Description : 这个类是 {@ThreadsExecutor} 的升级版
 * 提供了更多的功能和改进,例如 submit 等未实现的方法
 *
 * @Author mr li
 * @Version v2.0
 * @create 2025/02/07 09:33
 */
public class ThreadsExecutorV2 extends ThreadPoolExecutor {

    public ThreadsExecutorV2(int maximumPoolSize) {
        this(maximumPoolSize, 60L, TimeUnit.SECONDS);
    }

    public ThreadsExecutorV2(int maximumPoolSize, long keepAliveTime, TimeUnit unit) {
        super(maximumPoolSize, maximumPoolSize, // 核心线程数等于最大线程数
                keepAliveTime, unit,
                new LinkedBlockingQueue<>(), // 无界队列
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy() // 理论上不会被触发
        );
        super.allowCoreThreadTimeOut(true);// 允许核心线程超时销毁(关键配置)
    }

    public ThreadsExecutorV2(int maximumPoolSize, long keepAliveTime, TimeUnit unit, String namePrefix) {
        super(maximumPoolSize, maximumPoolSize, // 核心线程数等于最大线程数
                keepAliveTime, unit,
                new LinkedBlockingQueue<>(), // 无界队列
                new ThreadFactory() {
                    private int count = 0;

                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r, namePrefix + "-" + count++);
                    }
                },
                new ThreadPoolExecutor.AbortPolicy() // 理论上不会被触发
        );
        super.allowCoreThreadTimeOut(true);// 允许核心线程超时销毁(关键配置)
    }

    public ThreadsExecutorV2(int maximumPoolSize, String namePrefix) {
        this(maximumPoolSize, 60L, TimeUnit.SECONDS, namePrefix);
    }


    /**
     * (方法已禁用)覆盖父类的allowCoreThreadTimeOut方法,防止第三方调用。
     * 抛出UnsupportedOperationException
     */
    @Override
    public void allowCoreThreadTimeOut(boolean value) {
        throw new UnsupportedOperationException("This operation is not supported.");
    }


    /**
     * 使用例子
     *
     * @param args
     */
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = new ThreadsExecutorV2(3, "mine");
        bingfa(100, () -> {
            executor.execute(() -> {
                System.out.println("Thread: " + Thread.currentThread().getName() + " " + Thread.currentThread().getId());
                try {
                    Thread.sleep((long) (Math.random() * 1000));// 模拟方法执行时间
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            });
        });
        System.out.println("overoveroverover");
    }

    private static void bingfa(int bingfaSize, Runnable command) throws InterruptedException {
        final int concurrencyLevel = bingfaSize; // 并发量
        ExecutorService executor = Executors.newFixedThreadPool(concurrencyLevel);
        CountDownLatch startSignal = new CountDownLatch(1); // 开始信号
        CountDownLatch endSignal = new CountDownLatch(concurrencyLevel); // 结束信号
        // 提交并发任务
        for (int i = 0; i < concurrencyLevel; i++) {
            final int txt = i;
            executor.submit(() -> {
                try {
                    startSignal.await();    // 等待开始信号
                    command.run();                    // 调用目标方法
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    endSignal.countDown();  // 标记当前任务完成
                }
            });
        }
        startSignal.countDown(); // 触发所有任务同时开始
        endSignal.await();       // 等待所有任务完成
        executor.shutdown();     // 关闭线程池
    }


}