手写一个简单的线程池MyThreadPool

说明

手写的一个简单的线程池,旨在帮助了解线程池的工作原理。

核心内容

  1. 核心工作线程
  2. 任务阻塞队列

定义一个内部类去实现核心工作线程

    /**
     * 内部类:工作的核心线程
     */
    private final class WorkerThread extends Thread {
        String name;

        //构造方法
        WorkerThread(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            while (!getPoolState()) {
                try {
                    Runnable task = taskQueue.take();
                    if (task != null) {
                        getThreadLog("任务开始执行:" + task.toString());
                        task.run();
                    }
                    //释放内存
                    task = null;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            System.out.println("线程关闭");
        }
    }

使用一个阻塞队列存放需要处理的任务列表

    //存放任务执行结束的队列
    private volatile BlockingQueue<Runnable> taskQueue;
    //记录线程池中线程的个数
    private final Set<WorkerThread> workerThreadSet = new HashSet<>();

完整测试代码

package com.leo.demo.threadtest.mythreadpool;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName: MyThreadPool
 * @Description: 小的线程池模型
 * 1、线程池的
 * @Author: leo825
 * @Date: 2020-05-11 23:08
 * @Version: 1.0
 */
public class MyThreadPool {
    //核心线程数
    private int corePoolSize;
    //最大线程数
    private int maximumPoolSize;
    //存放任务执行结束的队列
    private volatile BlockingQueue<Runnable> taskQueue;
    //记录线程池中线程的个数
    private final Set<WorkerThread> workerThreadSet = new HashSet<>();
    //当前存放当前线程数
    private int workerCount = 0;
    //线程池关闭状态
    private volatile boolean THREADPOOL_SHUTDOWN = false;

    /**
     * 线程池构造方法,先不考虑参数校验问题
     *
     * @param corePoolSize
     * @param maximumPoolSize
     * @param taskQueue
     */
    MyThreadPool(int corePoolSize, int maximumPoolSize, BlockingQueue<Runnable> taskQueue) {
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.taskQueue = taskQueue;
        //构造线程池中的线程
        for (int i = 0; i < corePoolSize; i++) {
            WorkerThread workerThread = new WorkerThread("poolThread_" + i);
            workerThread.start();
            workerThreadSet.add(workerThread);
            workerCount++;
        }
    }

    /**
     * 向线程池中提交任务执行结束
     *
     * @param task
     */
    public void submit(Runnable task) {
        if (taskQueue.offer(task)) {
            getThreadLog("任务执行结束添加成功: " + task.toString());
        } else {
            getThreadLog("任务执行结束添加失败: " + task.toString());
        }
    }

    /**
     * 关闭线程池
     */
    public void shutdown() {
        getThreadLog("关闭线程池");
        THREADPOOL_SHUTDOWN = true;
    }

    /**
     * 内部类:工作的核心线程
     */
    private final class WorkerThread extends Thread {
        String name;

        //构造方法
        WorkerThread(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            while (!THREADPOOL_SHUTDOWN) {
                try {
                    Runnable task = taskQueue.take();
                    if (task != null) {
                        getThreadLog("任务开始执行:" + task.toString());
                        task.run();
                    }
                    //释放内存
                    task = null;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            getThreadLog("线程关闭");
        }
    }

    /**
     * 获取线程名和时间
     *
     * @return
     */
    public static void getThreadLog(String logContent) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("[");
        stringBuffer.append(Thread.currentThread().getName());
        stringBuffer.append(" ");
        stringBuffer.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()));
        stringBuffer.append("] ");
        stringBuffer.append(logContent);
        System.out.println(stringBuffer.toString());
    }

    /**
     * 测试main方法
     *
     * @param args
     */
    public static void main(String[] args) throws InterruptedException {
        //定义一个阻塞队列存放任务
        BlockingQueue<Runnable> workQueue = new LinkedBlockingDeque<>(5);
        //构造自己的线程池
        MyThreadPool threadPool = new MyThreadPool(3, 5, workQueue);
        //任务执行结束数量
        int size = 15;
        for (int i = 0; i < size; i++) {
            threadPool.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        int times = ThreadLocalRandom.current().nextInt(2, 6);
                        TimeUnit.SECONDS.sleep(times);
                        getThreadLog("任务执行结束 " + this.toString() + ",执行时长:" + times + " 秒");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        //休息20秒
        TimeUnit.SECONDS.sleep(20);
        //关闭线程池,此处不管用的,待后续分析源码
        threadPool.shutdown();
    }
}



测试结果如下:

[Thread-0 2020-06-09 11:32:12.698] 任务开始执行:com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@3fee733d
[main 2020-06-09 11:32:12.696] 任务执行结束添加成功: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@3fee733d
[main 2020-06-09 11:32:12.699] 任务执行结束添加成功: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@2a84aee7
[main 2020-06-09 11:32:12.699] 任务执行结束添加成功: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@a09ee92
[main 2020-06-09 11:32:12.699] 任务执行结束添加成功: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@30f39991
[main 2020-06-09 11:32:12.700] 任务执行结束添加成功: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@452b3a41
[main 2020-06-09 11:32:12.700] 任务执行结束添加成功: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@4a574795
[main 2020-06-09 11:32:12.700] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@f6f4d33
[main 2020-06-09 11:32:12.701] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@23fc625e
[main 2020-06-09 11:32:12.701] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@3f99bd52
[main 2020-06-09 11:32:12.701] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@4f023edb
[main 2020-06-09 11:32:12.702] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@3a71f4dd
[main 2020-06-09 11:32:12.703] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@7adf9f5f
[main 2020-06-09 11:32:12.703] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@85ede7b
[main 2020-06-09 11:32:12.703] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@5674cd4d
[main 2020-06-09 11:32:12.704] 任务执行结束添加失败: com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@63961c42
[Thread-1 2020-06-09 11:32:12.709] 任务开始执行:com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@2a84aee7
[Thread-2 2020-06-09 11:32:12.711] 任务开始执行:com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@a09ee92
[Thread-0 2020-06-09 11:32:14.712] 任务执行结束 com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@3fee733d,执行时长:2[Thread-0 2020-06-09 11:32:14.714] 任务开始执行:com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@30f39991
[Thread-1 2020-06-09 11:32:16.710] 任务执行结束 com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@2a84aee7,执行时长:4[Thread-1 2020-06-09 11:32:16.711] 任务开始执行:com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@452b3a41
[Thread-2 2020-06-09 11:32:17.712] 任务执行结束 com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@a09ee92,执行时长:5[Thread-2 2020-06-09 11:32:17.712] 任务开始执行:com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@4a574795
[Thread-0 2020-06-09 11:32:17.715] 任务执行结束 com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@30f39991,执行时长:3[Thread-1 2020-06-09 11:32:19.711] 任务执行结束 com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@452b3a41,执行时长:3[Thread-2 2020-06-09 11:32:21.713] 任务执行结束 com.leo.demo.threadtest.mythreadpool.MyThreadPool$1@4a574795,执行时长:4[main 2020-06-09 11:32:32.704] 关闭线程池

问题和思考

以上就是一个很小的线程池的模型,这个模型还存在很多问题。

  1. 线程池的最大线程数是核心线程满、阻塞队列满之后线程池扩展到最大线程数,线程池扩容是如何实现的?
  2. 线程空闲后是如何进行销毁的?
  3. 线程池相关的监控指标,历史最大线程数、当前线程数、累计执行任务数?
  4. 线程池是如何销毁的?
  5. 如果taskQueue队列满了,如何管理容量?
  6. 如果taskQueue中没有任务了,线程池活跃线程数如何看?

猜你喜欢

转载自blog.csdn.net/u011047968/article/details/106081789