手写简单的线程池

关于线程池的详细分析,具体请看这篇帖子:https://www.cnblogs.com/reecelin/p/12334107.html

在开始之前,我们还是再来复习一下线程池的工作流程吧,如下所示:

手写简单的线程池

现在,我们可以根据上面的流程简单写个线程池,如下:

public interface ThreadPool {


    /**
     *  添加任务
     * @param command
     * @return
     */
    boolean submit(Runnable command);


    /**
     * 关闭线程池,若有任务,则等待 任务执行完毕
     */
    void shutDown();

    /**
     * 立即关闭线程池
     */
    void shutDownNow();
}
public class MyThreadPool implements ThreadPool {


    //当前正在工作的线程数
    private int currentNum;

    //核心线程数
    private int corePoolSize;
    //最大核心线程数
    private static final int MAX_CORE_POOL_SIZE = 3;

    //线程池能容纳的最大线程数
    private int maxPoolSize;

    //最大线程数
    private static final int MAX_POOL_SIZE = 6;

    //线程池是否启动
    private volatile boolean isRunning = true;

    //存放添加进线程池的任务队列
    private BlockingQueue<Runnable> queue;

    private int queueSize;

    //任务队列最大长度  这里设置的比较小是为了后面可以使用拒绝策略
    private static final int MAX_QUEUE_SIZE = 20;

    //存储用于执行添加进线程池中任务的工作线程队列
    private List<Worker> workers;

    private ReentrantLock lock=new ReentrantLock();

    public MyThreadPool() {
        this(MAX_CORE_POOL_SIZE, MAX_POOL_SIZE, MAX_QUEUE_SIZE);
    }

    public MyThreadPool(int corePoolSize, int maxPoolSize, int queueSize) {
        this.corePoolSize = corePoolSize > MAX_CORE_POOL_SIZE ? MAX_CORE_POOL_SIZE : corePoolSize;
        this.maxPoolSize = maxPoolSize > MAX_POOL_SIZE ? MAX_POOL_SIZE : maxPoolSize;
        this.queueSize = queueSize > MAX_QUEUE_SIZE ? MAX_QUEUE_SIZE : queueSize;
        queue = new LinkedBlockingQueue<>(this.queueSize);
        workers = Collections.synchronizedList(new ArrayList<>(this.maxPoolSize));
        intialThreadPool();
    }

    private void intialThreadPool() {
        for (int i = 1; i <= this.corePoolSize; i++) {
            Worker worker = new Worker("核心线程-" + i);
            workers.add(worker);
            worker.start();
            currentNum++;
            System.out.println(DateUtil.getFormat().format(new Date())+" 核心线程-" + i + " 启动,等待执行任务");
        }
    }


    @Override
    public boolean submit(Runnable command) {
        if (isRunning) {
            //若是核心线程数还没达到最大,则新建核心线程执行任务
        if (currentNum < MAX_CORE_POOL_SIZE) {
            String threadName = "新建核心线程-" + ++this.corePoolSize;
            Worker worker = new Worker(threadName, command);
            workers.add(worker);
            worker.start();
            currentNum++;
            return true;
        } else if (currentNum >= MAX_CORE_POOL_SIZE && currentNum < MAX_POOL_SIZE) {
            //若是队列未满,则直接添加进队列
            if (queue.offer(command)) {
                return true;
                //若是队列已满,则创建非核心线程去执行任务
            } else {
                String threadName = "非核心线程-" + (currentNum - MAX_CORE_POOL_SIZE);
                Worker worker = new Worker(threadName, command);
                workers.add(worker);
                worker.start();
                currentNum++;
                return true;

            }
            //若是线程数已到最大,且队列也满了,则直接执行拒绝策略
        } else if (currentNum >= MAX_POOL_SIZE && !queue.offer(command)) {
            System.out.println(DateUtil.getFormat().format(new Date())+" 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:"+queue.size());
            return false;
        }
    }
        return false;
    }


    @Override
    public void shutDown() {
        while (!queue.isEmpty()) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        isRunning = false;
        for (Worker worker : workers) {
            worker.interrupt();
            // help gc
            worker = null;
        }
        queue.clear();
    }

    @Override
    public void shutDownNow() {
        isRunning = false;
        for (Worker worker : workers) {
            worker.interrupt();
            // help gc
            worker = null;
        }
        queue.clear();
    }

    private class Worker extends Thread {


        private Runnable command;

        public Worker(String name) {
            super(name);
        }

        public Worker(String name, Runnable command) {
            super(name);
            this.command = command;
        }

        @Override
        public void run() {
            while (isRunning || !queue.isEmpty()) {
                if (command != null) {
                    command.run();
                    // help gc
                    command = null;
                } else {

                    command = queue.poll();
                    if (command != null) {
                        command.run();
                        // help gc
                        command = null;
                    }
                }
            }
        }

    }
}
public class MyTask implements Runnable {

    private int id;

    public MyTask(int id) {
        this.id = id;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"执行任务:"+id+" 完成");
    }
}
public class DateUtil {

    private static final String pattern="yyyy-MM-dd HH:mm:ss";

    private static volatile SimpleDateFormat format;

    private DateUtil(){}

    public static SimpleDateFormat getFormat(){
        if (format==null){
            synchronized (DateUtil.class){
                if (format==null){
                    format= new SimpleDateFormat(pattern);
                }
            }
        }
        return format;
    }
}
public class Test {
    public static void main(String[] args) {
        MyThreadPool pool=new MyThreadPool(2, 6, 20);

        for (int i = 1; i <=40 ; i++) {
            pool.submit(new MyTask(i));
        }
        pool.shutDown();
    }
}

运行测试类,控制台输出:

2020-02-22 20:29:56 核心线程-1 启动,等待执行任务
2020-02-22 20:29:56 核心线程-2 启动,等待执行任务
2020-02-22 20:29:56 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:20
2020-02-22 20:29:56 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:20
2020-02-22 20:29:56 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:20
2020-02-22 20:29:56 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:20
2020-02-22 20:29:56 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:20
2020-02-22 20:29:56 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:20
2020-02-22 20:29:56 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:20
2020-02-22 20:29:56 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:20
2020-02-22 20:29:56 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:20
2020-02-22 20:29:56 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:20
2020-02-22 20:29:56 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:20
2020-02-22 20:29:56 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:20
2020-02-22 20:29:56 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:20
2020-02-22 20:29:56 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:20
2020-02-22 20:29:56 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:20
2020-02-22 20:29:56 线程池已满负载运行,拒绝了该任务,当前任务队列大小为:20
2020-02-22 20:29:56 核心线程-1执行任务:2 完成
2020-02-22 20:29:56 核心线程-1执行任务:3 完成
2020-02-22 20:29:56 核心线程-1执行任务:4 完成
2020-02-22 20:29:56 核心线程-1执行任务:5 完成
2020-02-22 20:29:56 核心线程-1执行任务:6 完成
2020-02-22 20:29:56 核心线程-1执行任务:7 完成
2020-02-22 20:29:56 核心线程-1执行任务:8 完成
2020-02-22 20:29:56 核心线程-1执行任务:9 完成
2020-02-22 20:29:56 核心线程-1执行任务:10 完成
2020-02-22 20:29:56 核心线程-1执行任务:11 完成
2020-02-22 20:29:56 核心线程-1执行任务:12 完成
2020-02-22 20:29:56 核心线程-1执行任务:13 完成
2020-02-22 20:29:56 核心线程-1执行任务:14 完成
2020-02-22 20:29:56 核心线程-1执行任务:15 完成
2020-02-22 20:29:56 核心线程-1执行任务:16 完成
2020-02-22 20:29:56 核心线程-1执行任务:17 完成
2020-02-22 20:29:56 核心线程-1执行任务:18 完成
2020-02-22 20:29:56 核心线程-1执行任务:19 完成
2020-02-22 20:29:56 核心线程-1执行任务:20 完成
2020-02-22 20:29:56 核心线程-1执行任务:21 完成
2020-02-22 20:29:56 新建核心线程-3执行任务:1 完成
2020-02-22 20:29:56 非核心线程-1执行任务:23 完成
2020-02-22 20:29:56 非核心线程-0执行任务:22 完成
2020-02-22 20:29:56 非核心线程-2执行任务:24 完成

这个只是简单的线程池,许多功能都没有完善,但对于了解线程池的执行流程有一定帮助。后面会继续完善这个demo,使其更加完整。

上一篇:leetcode-面试题56-①。数组中出现的次数


下一篇:MySQL Boolean类型的坑