线程池原理以及自定义线程池

Posted junjie2019

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程池原理以及自定义线程池相关的知识,希望对你有一定的参考价值。

第一部分:对线程池的需求分析

/*
    8.1 线程池原理

    一个完整的线程池应该具备如下要素:
        1.任务队列:用于缓存提交的任务
        2.线程数量管理功能:可通个三个参数实现:
            init:创建时初始的线程数量
            max:线程池自动扩充时最大的线程数量
            core:空闲时但是需要释放线程,但是也要维护一定数量的活跃线程
        3.任务拒绝策略:
        4.线程工程:主要用于个性化定制线程,比如设置守护线程、设置线程名称等
        5.QueueSize:任务队列主要存放Runnable,防止内存溢出,需要有limit数量限制
        6.keepedalive时间:该时间主要决定线程各个重要参数自动维护的时间间隔

*/

 


 

 

第二部分:对线程池运行过程的简单分析

/*
    main:-------P----------------------------------------------
                |
    pool:       |-----A----B---C-------------------------------
                      |    |   |
       A:             |----|---|-------------------------------
                           |   |
       B:                  |---|-------------------------------
                               |
       C:                      |-------------------------------
 */

 


 

 

第三部分:接口定义

 

  ThreadPool接口:

public interface ThreadPool {

    //提交任务到线程池
    void execute(Runnable runnable);

    //关闭线程池
    void shutdown();

    //获取线程池的初始化大小
    int getInitSize();

    //获取线程池最大的线程数
    int getMaxSize();

    //获取线程池的核心线程数量
    int getCoreSize();

    //获取线程池中活跃线程数量
    int getActiveCount();

    //获取线程池中用于缓存任务队列的大小
    int getQueueSize();

    //查看线程池是否已经别shutdown
    boolean isShutdown();

}

 

  RunnableQueue接口:

//任务多列,主要用于缓存提交到线程池中的任务
public interface RunnableQueue{

    //当有新的任务捡来时首先会offer到队列中
    void offer(Runnable runnable);

    //工作线程通过take方法获取Runnable
    Runnable take() throws InterruptedException;

    //获取任务队列中任务的数量
    int size();

}

 

  DenyPolicy接口:

@FunctionalInterface
public interface DenyPolicy{

    void reject(Runnable runnable,ThreadPool threadPool);
}

 


 

 

第四部分:定义异常

  RunnableDenyException:

public class RunnableDenyException extends RuntimeException{
    public RunnableDenyException(String msg){
        super(msg);
    }
}

 


 

 

第五部分:实现DenyPolicy

  ——实际上采用的是在接口中直接实现的

@FunctionalInterface
public interface DenyPolicy{
    void reject(Runnable runnable,ThreadPool threadPool);

    //该策略会直接将任务丢弃
    class DiscardDenyPolicy implements DenyPolicy{

        @Override
        public void reject(Runnable runnable, ThreadPool threadPool) {
            //do nothing
        }
    }

    //该策略会向任务提交这抛出异常
    class AbortDenyPolicy implements DenyPolicy{

        @Override
        public void reject(Runnable runnable, ThreadPool threadPool) {
            throw new RunnableDenyException("The runnable "+runnable+" will be abort.");
        }
    }

    //该策略会使任务在提交者所在的线程中执行任务
    class RunnerDenyPlolicy implements DenyPolicy{

        @Override
        public void reject(Runnable runnable, ThreadPool threadPool) {
            runnable.run();
        }
    }
}

 


 

 

第六部分:实现InternalTask

public class InternalTask implements Runnable{

    private final RunnableQueue runnableQueue;
    private volatile boolean running = true;

    public InternalTask(RunnableQueue runnableQueue){
        this.runnableQueue=runnableQueue;
    }

    /*
        对run方法的分析:
            如果当前任务为running且没有被中断,则将不断地从queue中获取Runnable
            然后执行run方法。让这个任务停止的方法是:
                1.在pool线程中,调用该线程对象的interrupt方法
                2.在pool线程中,调用该InternalTask对象的stop方法
                    ——这也就解释了为什么在BasicThreadPool中
                        将InternalTask对象和执行InternalTask对象
                        的线程组合在一起保存。
     */
    @Override
    public void run() {
        while(running&&!Thread.currentThread().isInterrupted()){
            try {
                Runnable task = runnableQueue.take();
                task.run();
            } catch (InterruptedException e) {
                running = false;
                break;
            }
        }
    }

    public void stop(){
        this.running = false;
    }
}

 


 

 

第七部分:实现RunableQueue

import java.util.LinkedList;

public class LinkedRunnableQueue implements RunnableQueue{

    private final int limit;
    private final DenyPolicy denyPolicy;
    private final ThreadPool threadPool;

    /*
        这个地方有个很LinkedList的用法经验:
            addLast():从队列的尾部添加一个元素
            removeFirst():从队列的头部拿出一个元素
     */
    private final LinkedList<Runnable> runnableList = new LinkedList<>();

    public LinkedRunnableQueue(int limit, DenyPolicy denyPolicy, ThreadPool threadPool) {
        this.limit = limit;
        this.denyPolicy = denyPolicy;
        this.threadPool = threadPool;
    }


    @Override
    public void offer(Runnable runnable) {
        synchronized (runnableList){
            if(runnableList.size()>=limit){
                denyPolicy.reject(runnable,threadPool);
            }else {
                runnableList.addLast(runnable);
                runnableList.notifyAll();
            }
        }
    }

    @Override
    public Runnable take() throws InterruptedException {
        synchronized (runnableList) {
            while (runnableList.isEmpty()) {
                try {
                    /*
                        如果任务队列中没有可执行的任务,则当前线程将会被挂起,
                        所以在offer中,当队列中添加成员后,需要调用notifyAll
                     */
                    runnableList.wait();
                } catch (InterruptedException e) {
                    /*
                        写法分析:
                            其实这个地方可以不用这么写,我就写一个wait,然后在方法上将其抛出去,
                            这也是允许的。
                     */
                    throw e;
                }
            }
            return runnableList.removeFirst();
        }
    }

    @Override
    public int size() {
        synchronized (runnableList){
            return runnableList.size();
        }
    }
}

 


 

 

第八部分:实现ThreadPool

import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.TimeUnit;

public class BasicThreadPool extends Thread implements ThreadPool {

    private final static DenyPolicy DEFAULT_DENY_POLICY = new DenyPolicy.DiscardDenyPolicy();
    private final static ThreadFactory DEFAULT_THREAD_FACTORY = new ThreadFactory.DefaultThreadFactory();


    private int initSize;
    private int maxSize;
    private int coreSize;
    private int activeCount;

    private final ThreadFactory threadFactory;
    private final RunnableQueue runnableQueue;
    private final long keepAliveTime;
    private final TimeUnit timeUnit;

    private volatile boolean isShutdown = false;

    /*
        稍微注意下这些容器的写法
     */
    private final Queue<ThreadTask> threadQueue=new ArrayDeque<>();

    public BasicThreadPool(int initSize, int maxSize, int coreSize,int queueSize){
        this(initSize,maxSize,coreSize,DEFAULT_THREAD_FACTORY,
                queueSize,DEFAULT_DENY_POLICY,10,TimeUnit.SECONDS);
    }

    public BasicThreadPool(int initSize, int maxSize, int coreSize,
                           ThreadFactory threadFactory, int queueSize,
                           DenyPolicy denyPolicy, long keepAliveTime,
                           TimeUnit timeUnit) {
        this.initSize = initSize;
        this.maxSize = maxSize;
        this.coreSize = coreSize;

        this.threadFactory = threadFactory;

        this.runnableQueue=new LinkedRunnableQueue(queueSize,denyPolicy,this);

        this.keepAliveTime = keepAliveTime;
        this.timeUnit = timeUnit;

        this.init();
    }



    //创建这个线程池的线程,执行这个方法
    private void init(){
        start();
        for (int i = 0; i < initSize; i++) {
            newThread();
        }
    }

    private void newThread() {
        /*
            如果Pool本身只保存internalTask,则InternalTask需要集成许多对
            任务的管理,但是它终究只是一个Runnable,所以并不现实
         */
        InternalTask internalTask = new InternalTask(runnableQueue);
        Thread thread = this.threadFactory.createThread(internalTask);
        ThreadTask threadTask = new ThreadTask(thread,internalTask);
        threadQueue.offer(threadTask);
        this.activeCount++;
        thread.start();
    }

    //从线程池中移除某个线程
    private void removeThread(){

        ThreadTask threadTask = threadQueue.remove();
        /*
            当调用stop方法是,循环将会不被执行,线程也就自然的结束了
            生命周期。
         */
        threadTask.internalTask.stop();
        this.activeCount--;
    }

    //维护线程数量,比如扩容、回收等工作
    public void run(){
        /*
            只有调用了Pool的shutdown方法,或者对其中断了,才后导致其
            退出循环。
                ——很奇怪的一点哦,我直接把Pool线程给退出了,Pool
                    线程创建的线程我不进行管理了么。
         */
        while(!isShutdown&&!isInterrupted()){
            try{
                timeUnit.sleep(keepAliveTime);
            } catch (InterruptedException e) {
                isShutdown=true;
                break;
            }
            synchronized (this){
                //多次确认,是否关闭这个线程了。。。
                if(isShutdown)
                    break;

                //当线程中有任务尚未处理,并且activeCount<coreSize则继续扩容
                if(runnableQueue.size()>0&&activeCount<coreSize){
                    for (int i = initSize; i < coreSize; i++) {
                        newThread();
                    }
                    /*
                        书中说continue的目的是,不想让线程的扩容直接到达maxsize。
                        这个continue会导致while循环重新判断,从而导致该线程睡眠
                        keepAliveTime时间。
                     */
                    continue;
                }

                //当前队列中有任务尚未处理,并且activeCount<maxSize则kuorong
                if (runnableQueue.size() > 0 && activeCount < maxSize) {
                    for (int i = coreSize; i < maxSize; i++) {
                        newThread();
                    }
                }

                //如果任务队列中没有任务,则需要回收,回收至coreSize即可
                if(runnableQueue.size()==0&&activeCount>coreSize){
                    for (int i = coreSize; i < activeCount; i++) {
                        removeThread();
                    }
                }
            }
        }
    }

    @Override
    public void execute(Runnable runnable) {
        if(this.isShutdown){
            throw new IllegalStateException("The thread pool is destory");
        }
        this.runnableQueue.offer(runnable);
    }

    /*
        问题还是存在着,而且现在更尴尬了,如果pool被interrupt了,那么
        shutdown清理线程部分就永远都不会执行了。
     */
    @Override
    public void shutdown() {
        if(isShutdown)
            return;

        isShutdown=true;

        threadQueue.forEach(threadTask -> {
            threadTask.internalTask.stop();
            threadTask.thread.interrupt();
        });
    }

    @Override
    public int getInitSize() {
        if(this.isShutdown){
            throw new IllegalStateException("The thread pool is destory");
        }
        return initSize;
    }

    @Override
    public int getMaxSize() {
        if(this.isShutdown){
            throw new IllegalStateException("The thread pool is destory");
        }
        return maxSize;
    }

    @Override
    public int getCoreSize() {
        if(this.isShutdown){
            throw new IllegalStateException("The thread pool is destory");
        }
        return coreSize;
    }

    @Override
    public int getActiveCount() {
        synchronized (this){
            return this.activeCount;
        }
    }

    @Override
    public int getQueueSize() {
        if(this.isShutdown){
            throw new IllegalStateException("The thread pool is destory");
        }
        return runnableQueue.size();
    }

    @Override
    public boolean isShutdown() {
        return this.isShutdown;
    }

    private static class ThreadTask{
        Thread thread;
        InternalTask internalTask;

        public ThreadTask(Thread thread, InternalTask internalTask) {
            this.thread = thread;
            this.internalTask = internalTask;
        }
    }
}

 


 

 

第九部分:测试

import java.util.concurrent.TimeUnit;

public class Test {
    public static void main(String[] args){
        ThreadPoolTest.test();
    }
}

class ThreadPoolTest{
    public static void test(){
        final ThreadPool threadPool = new BasicThreadPool(2,6,4,1000);

        for (int i = 0; i < 20; i++) {
            threadPool.execute(()->{
                try{
                    TimeUnit.SECONDS.sleep(10);
                    System.out.println(Thread.currentThread().getName()+
                        " is running and done.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        while (true) {
            System.out.println("getActiveCount:"+threadPool.getActiveCount());
            System.out.println("getQueueSize:"+threadPool.getQueueSize());
            System.out.println("getCoreSize:"+threadPool.getCoreSize());
            System.out.println("getMaxSize:"+threadPool.getMaxSize());
            System.out.println("=======================================");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

 

以上是关于线程池原理以及自定义线程池的主要内容,如果未能解决你的问题,请参考以下文章

线程池工作原理

java线程池原理便懂了!♥♥

只需这篇文章java线程池原理便懂了!♥♥

Java线程池之线程池原理

Android线程管理之ThreadPoolExecutor自定义线程池

自定义线程池理论知识部分