【java】手写一个线程池

在手写一个线程池前,我们先参考一下JDK里的线程池是怎么工作的。

一、JDK线程池的七大参数

1.corePoolSize:线程池中常驻核心线程数
2.maximumPoolSize:线程池能够容纳同时执行的最大线程数,必须大于等于1
3.keepAliveTime:多余的空闲线程的存活时间,当前线程池数量超过corePoolSize时,
4.unit:keepAliveTime的单位
5.workQueue:任务队列,被提交但尚未被执行的任务
6.threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程一般用默认的即可
这个简单理解成是xxx银行的标志,默认不用管。
7.handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时如何来拒绝请求执行的runable的策略

二、线程池的工作流程

线程池的工作流程
明白了JDK线程池的基本元素与工作流程之后,我们模仿它写一个简单的线程池

三、写一个线程池类

首先定义一个线程池接口

public interface ThreadPool {
    /**
     * 执行具体的task
     */
    void excute(Runnable task);
    /**
     * 处理提交的任务
     *
     * @param task
     */
    void submit(Runnable task);

}

然后实现它。

这里我们不按照JDK线程池的工作原理,而是先实现一个简单的线程池:初始化一批常驻线程,然后每新来一个任务,就把它放到阻塞队列中,让这些线程自己去队列中取任务消费。

public class MThreadPool implements ThreadPool {

    //线程数量
    private int workNum;
    //任务数量
    private int taskNum;
    //任务【阻塞】队列,被提交但尚未被执行的任务
    private BlockingQueue<Runnable> taskQueue;
    //表示生成线程池中工作线程的线程工厂
    private ThreadFactory threadFactory;


    //存放工作线程的容器
    private final Set<WorkerThread> workers = new HashSet();

    //初始化线程池
    public MThreadPool(int workNum, BlockingQueue blockingQueue, ThreadFactory threadFactory){
        this.workNum = workNum;
        this.taskQueue = blockingQueue;
        this.threadFactory = threadFactory;
        initWorker();
    }

    public void initWorker(){
        //启动一定数量的线程数,从队列中获取任务处理
        for (int i=0;i<workNum;i++) {
            WorkerThread workThread = new WorkerThread("thead_"+i, threadFactory);
            workThread.start();
            workers.add(workThread);
        }
    }


    //工作线程类
    private class WorkerThread extends Thread{

        public WorkerThread(String name, ThreadFactory factory){
            setName(name);
            factory.newThread(this);
        }

        @Override
        public void run() {
            Runnable runnable = null;
            try {
                while (! isInterrupted()) {  //如果没有被标记中断,则从对阻塞队列中取出任务执行
                    runnable = taskQueue.get();  //take:阻塞接口的移除方法
                    if (runnable != null) {
                        System.out.println("Thread ID:" + getName() + " ready exec:" + runnable.toString());
                        runnable.run();
                    }
                    runnable = null;  //help gc
                }
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
        //线程停止工作
        public void stopWork() {
            interrupt();
        }
    }

    @Override
    public void excute(Runnable task) {

        try {
            taskQueue.put(task);   //put:阻塞接口的插入
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

    @Override
    public void destory() {
        for(WorkerThread workerThread:workers){
            workerThread.stopWork();
        }
    }


}

在这个实现中,线程池在初始化的时候就创建了工作线程,工作线程直接消费队列中的任务。这个实现中,线程池并不会根据任务数量灵活的创建、销毁线程。如果队列中没有任务,线程将空等,消耗性能。现在,我们以上面的实现作为基础,将JDK线程池的设计思想加进来。

public class MXThreadPool extends Thread implements ThreadPool {


    //任务【阻塞】队列,被提交但尚未被执行的任务
    private BlockingQueue<Runnable> taskQueue;
    //表示生成线程池中工作线程的线程工厂
    private ThreadFactory threadFactory;
    //最大线程数
    private int maxSize;
    //核心线程数
    private int coreSize;
    //线程存活时间
    private long keepAliveTime;
    //当前活跃线程的数量
    private int activeCount;
    //存放工作线程的容器
    private final Set<WorkerThread> workers = new HashSet();

    //初始化线程池
    public MXThreadPool(int maxSize, int coreSize, BlockingQueue blockingQueue,
                        ThreadFactory threadFactory, long keepAliveTime){
        this.maxSize = maxSize;
        this.coreSize = coreSize;
        this.taskQueue = blockingQueue;
        this.threadFactory = threadFactory;
        this.keepAliveTime = keepAliveTime;
        this.activeCount = 0;
    }
    
    //创建新的任务线程并启动
    private void newThread() {
        WorkerThread workThread = new WorkerThread("thead_"+this.activeCount++, threadFactory);
        workThread.start();
        workers.add(workThread);
    }

    //移除一个工作线程
    private void removeThread() {
        Iterator<WorkerThread> iterator = workers.iterator();
        if(iterator.hasNext()){
            WorkerThread workerThread = iterator.next();
            workerThread.stopWork();
            this.activeCount--;
        }
    }

    @Override
    public void run() {
        //自动维护线程池
        while (!isInterrupted()) {
            try {
                Thread.sleep(keepAliveTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
                break;
            }
            synchronized (this) {
                //当任务队列大于0,活跃线程小于核心线程的时候,扩容线程
                if (taskQueue.size() > 0 && activeCount < coreSize) {
                    for (int i = 0; i < coreSize-activeCount; i++) {
                        newThread();
                    }
                    continue;
                }
                //当任务队列大于0,活跃线程小于最大线程的时候,扩容线程
                if (taskQueue.size() > 0 && activeCount < maxSize) {
                    for (int i = 0; i < maxSize-activeCount; i++) {
                        newThread();
                    }
                }
                //当任务队列等于0,活跃线程大于核心线程的时候,缩减线程
                if (taskQueue.size() == 0 && activeCount > coreSize) {
                    for (int i = 0; i < activeCount-coreSize; i++) {
                        removeThread();
                    }
                }

            }
        }
    }


    //工作线程类
    private class WorkerThread extends Thread{

        public WorkerThread(String name, ThreadFactory factory){
            setName(name);
            factory.newThread(this);
        }

        @Override
        public void run() {
            Runnable runnable = null;
            try {
                while (! isInterrupted()) {  //如果没有被标记中断,则从对阻塞队列中取出任务执行
                    runnable = taskQueue.get();  //take:阻塞接口的移除方法
                    if (runnable != null) {
                        System.out.println("Thread ID:" + getName() + " ready exec:" + runnable.toString());
                        runnable.run();
                    }
                    runnable = null;  //help gc
                }
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
        //线程停止工作
        public void stopWork() {
            interrupt();
        }
    }

    @Override
    public void excute(Runnable task) {

        try {
            taskQueue.put(task);   //put:阻塞接口的插入
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

    @Override
    public void destory() {
        for(WorkerThread workerThread:workers){
            workerThread.stopWork();
        }
    }

}

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页