手写实现简易版线程池

手写实现简易版线程池

首先封装自己的Task任务类

package com.im.socket.cdn.xiaoke;

import cn.hutool.cron.task.Task;

/**
 * @Author: 无敌代码写手
 * @CreateTime: 2025年09月09日
 */
public class ChxTask implements Task {

    private String id;

    private Task task;

    public ChxTask(String id,Task task){
        this.id = id;

        this.task = task;
    }

    @Override
    public void execute() {
        this.task.execute();
    }

    public String getId() {
        return this.id;
    }
}

这里我封装了一个Task,实现Task接口,然后新增id字段,这样我们可以看到每个被处理的任务ID。
然后封装一下Thread类

package com.im.socket.cdn.xiaoke;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class ChxThread implements Runnable {

    private final LinkedBlockingQueue<ChxTask> taskQueue;
    private final boolean isCore;
    private final long keepAliveMillis;
    private final ChxThreadPool pool;

    public ChxThread(LinkedBlockingQueue<ChxTask> taskQueue, boolean isCore, long keepAliveMillis, ChxThreadPool pool) {
        this.taskQueue = taskQueue;
        this.isCore = isCore;
        this.keepAliveMillis = keepAliveMillis;
        this.pool = pool;
    }

    @Override
    public void run() {
        try {
            while (true) {
                if (Thread.currentThread().isInterrupted()) break;

                ChxTask task;
                if (isCore) { // 如果是核心线程
                    task = taskQueue.take(); // 核心线程永远阻塞
                } else {
                // 如果非核心线程,等待最大超时时间
                    task = taskQueue.poll(keepAliveMillis, TimeUnit.MILLISECONDS);
                    if (task == null) {
                        System.out.println(Thread.currentThread().getName() + " 超时空闲,自动销毁");
                        break; // 非核心线程空闲超时退出
                    }
                }

                if (task != null) {
                    System.out.println(Thread.currentThread().getName() + " 执行任务ID:" + task.getId());
                    task.execute();
                }
            }
        } catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName() + " 被中断退出");
        } finally {
            pool.removeThread(Thread.currentThread()); // 移除线程
        }
    }
}

这里仿照JDK官方的ThreadPool进行设计,封装的参数有:

  • taskQueue:任务队列
  • isCroe:是否为核心线程
  • keepAliveMillis:最大等待时间
  • pool:线程池
    关键代码:
       task = taskQueue.poll(keepAliveMillis, TimeUnit.MILLISECONDS);
        if (task == null) {
			System.out.println(Thread.currentThread().getName() + " 超时空闲,自动销毁");
             break; // 非核心线程空闲超时退出
		}

这一段代码是用来非核心线程是否应该自动 销毁的,如果是非核心线程,并且任务队列 为空,队列会等待最大超时时间,如果等待超时还没有任务进入队列就会返回空,那么该非核心线程就可以被销毁。
接下来是封装的线程池类ChxThreadPool:

package com.im.socket.cdn.xiaoke;

import cn.hutool.cron.task.Task;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * 自定义线程池
 */
public class ChxThreadPool {

    private final int coreSize;
    private final int maxSize;
    private final int queueSize;
    private final long keepAliveMillis;

    private final List<Thread> threads;
    private final LinkedBlockingQueue<ChxTask> queue;

    private volatile boolean running = true;

    public ChxThreadPool(int coreSize, int maxSize, int queueSize, long keepAliveMillis) {
        this.coreSize = coreSize;
        this.maxSize = maxSize;
        this.queueSize = queueSize;
        this.keepAliveMillis = keepAliveMillis;

        this.queue = new LinkedBlockingQueue<>(queueSize);
        this.threads = new ArrayList<>(maxSize);

        // 启动核心线程
        for (int i = 0; i < this.coreSize; i++) {
            Thread thread = new Thread(new ChxThread(queue, true, keepAliveMillis, this));
            thread.start();
            threads.add(thread);
        }
    }


    public synchronized void execute(Task task) {
        if (!running) {
            throw new RuntimeException("线程池已关闭,无法提交任务");
        }

        if (!queue.offer(new ChxTask(IdWorker.getIdStr(), task))) {  // 队列满了
            if (threads.size() < maxSize) {  // 可以扩容
                Thread t = new Thread(new ChxThread(queue, false, keepAliveMillis, this));
                t.start();

                threads.add(t);
                System.out.println("扩容线程:" + t.getName() + "已加入线程池");

                try {
                    queue.put(new ChxTask(IdWorker.getIdStr(), task));  // 阻塞直到有空位
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("任务提交被中断", e);
                }

            } else {  // 队列满且线程池满
                throw new RuntimeException("队列与线程池已满,拒绝任务");
            }
        }

    }

    /**
     * 从线程池集合中移除已退出线程
     */
    protected synchronized void removeThread(Thread t) {
        threads.remove(t);
        System.out.println(t.getName() + " 已从线程池移除");
    }

    /**
     * 优雅关闭线程池
     */
    public void shutdown() {
        running = false;
        synchronized (threads) {
            for (Thread t : threads) {
                t.interrupt();
            }
        }
    }

    public int getActiveThreadCount() {
        return threads.size();
    }

    public int getQueueSize() {
        return queue.size();
    }
}

构造方法:

  • coreSize:核心线程个数
  • maxSize:最大支持多少线程数
  • queueSize:任务队列容量
  • keepAliveMillis:非核心线程空闲时最大存活时间
    在构造方法中,根据核心线程数创建N个线程并存入threas线程集合中。
    核心代码:
    public synchronized void execute(Task task) {
        if (!running) {
            throw new RuntimeException("线程池已关闭,无法提交任务");
        }

        if (!queue.offer(new ChxTask(IdWorker.getIdStr(), task))) {  // 队列满了
            if (threads.size() < maxSize) {  // 可以扩容
                Thread t = new Thread(new ChxThread(queue, false, keepAliveMillis, this));
                t.start();

                threads.add(t);
                System.out.println("扩容线程:" + t.getName() + "已加入线程池");

                try {
                    queue.put(new ChxTask(IdWorker.getIdStr(), task));  // 阻塞直到有空位
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("任务提交被中断", e);
                }

            } else {  // 队列满且线程池满
                throw new RuntimeException("队列与线程池已满,拒绝任务");
            }
        }

    }

该方法是线程池执行任务的方法,当用户扔进来一个任务,会尝试将他放进任务队列中,如果队列满了,会开启新线程进行处理。如果任务队列和最大线程都到满了,则会抛出异常(这里大家可以优化,我这个地方是为了看的更直观一些,抛出了异常)。
线程池运行流程:

  1. 有任务进来,使用核心线程处理
  2. 核心线程忙碌,先将任务放入任务队列
  3. 任务队列满了,开启非核心线程
  4. 非核心线程满了,拒绝任务

当时我想过修改流程的,我想核心线程忙碌直接开启非核心线程,然后非核心线程满了在存入任务队列,流程如下:

  1. 有任务进来,使用核心线程处理
  2. 核心线程忙碌,开启非核心线程处理
  3. 非核心线程满了,存入任务队列
  4. 任务队列程满了,拒绝任务

该操作在处理的方面虽然是快了不少,但是会早成性能开销比较严重。有更好想法的小伙伴可以评论交流。

最终使用:

package com.im.socket.cdn.xiaoke;

/**
 * @Author: 无敌代码写手
 * @CreateTime: 2025年09月09日
 */
public class ThreadDemo {


    public static void main(String[] args) {

        ChxThreadPool chxThreadPool = new ChxThreadPool(20, 50, 100,5000L);
        for (int i = 0; i < 180; i++) {
            int finalI = i;
            chxThreadPool.execute(() -> {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("你好"+ finalI);
            });
        }

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值