Java高并发编程学习--17. 线程的ThreadPool

本文介绍了ThreadPool原理,一个完整线程池应具备任务队列、线程数量管理功能、任务拒绝策略、线程工厂等要素。还给出线程池实现例子,包含多个接口和类,如ThreadPool.java、ThreadFactory.java等,并展示了运行结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、ThreadPool原理

  • 所谓线程池,通俗的理解就是有一个池子,里面存放着已经创建好的线程,当有任务提交给线程池执行时,池子中的某个线程会主动执行该任务力如果池子中的线程数量不够应付数量众多的任务时,则需要自动扩充新的线程到池子中,但是该数量是有限的,就好比池塘的水界线一样。当任务比较少的时候,池子中的线程能够自动回收,释放资源。为了能够异步地提交任务和缓存未被处理的任务,需要有一个任务队列,如图8.1所示。通过上面的描述可知,一个完整的线程池应该具备如下要素。
  1. 任务队列:用于缓存提交的任务。
  2. 线程数量管理功能:一个线程池必须能够很好地管理和控制线程数量,可通过如下三个参数来实现,比如创建线程池时初始的线程数量init;线程池自动扩充时最大的线程数量max;在线程池空闲时需要释放线程但是也要维护一定数量的活跃数量或者核心数量c。re。有了这三个参数,就能够很好地控制线程池中的线程数量,将其维护在一个合理的范围之内,三者之间的关系是init<=core«=maxo
  3. 任务拒绝策略:如果线程数量已达到上限且任务队列已满,则需要有相应的拒绝策略来通知任务提交者。
  4. 线程工厂:主要用于个性化定制线程,比如将线程设置为守护线程以及设置线程名称等。
  5. QueueSize:任务队列主要存放提交的Ru皿able,但是为了防止内存溢出,需要有limit数量对其进行控制。
  6. Keepedalive时间:该时间主要决定线程各个重要参数自动维护的时间间隔。

二、线程池实现例子

  1. ThreadPool.java接口,线程池基本操作
package p126_thread_pool;

/**
 * @ClassName ThreadPoll
 * @Description TODO
 * @Author Cays
 * @Date 2019/5/4 11:02
 * @Version 1.0
 **/
public interface ThreadPool {
    //提交任务到线程池
    void execute(Runnable runnable);
    //关闭线程池
    void shutdown();
    //获取线程池的初始化大小
    int getInitSize();
    //获取线程池的核心线程数量
    int getCoreSize();
    //获取线程池的最大线程数量
    int getMaxSize();
    //获取线程池中用于缓存任务队列的大小
    int getQueueSize();
    //获取线程池中活跃的线程的数量
    int getActiveCount();
    //查看线程池是否已经被shutdown
    boolean isShutdown();
}

  1. ThreadFactory.java接口,创建个性化线程
package p126_thread_pool;

/**
 * @ClassName ThreadFactory
 * @Description TODO
 * ThreadFactory提供创建线程的接口,以便个性化定制Thread,比如Thread应该被加入到哪个
 * Thread Group中,优先级、线程名称,以及是否为守护线程等
 * @Author Cays
 * @Date 2019/5/4 11:52
 * @Version 1.0
 **/
@FunctionalInterface
public interface ThreadFactory {
    Thread createThread(Runnable runnable);
}

  1. RunnableQueue.java接口,线程队列基本操作
package p126_thread_pool;

/**
 * @ClassName RunnableQueue
 * @Description TODO
 * RunnableQueue主要用于存放提交的Runnable,该Runnable是一个BlockedQueue,
 * 并且有limit限制
 * @Author Cays
 * @Date 2019/5/4 11:48
 * @Version 1.0
 **/
public interface RunnableQueue {
    //当有新的任务进来时首先会offer到队列中
    void offer(Runnable runnable);
    //工作线程通过take方法获取Runnable
    Runnable take() throws InterruptedException;
    //获取任务队列中任务的数量
    int size();
}

  1. DenyPolicy.java接口,线程池满时拒绝策略
package p126_thread_pool;
@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+" vill" +
                    " be abort.");
        }
    }
    //该拒绝策略会使任务在提交者所在的线程中执行任务
    class RunnableDenyPolicy implements DenyPolicy{
        @Override
        public void reject(Runnable runnable, ThreadPool threadPool) {
            if (!threadPool.isShutdown()){
                runnable.run();
            }
        }
    }
}

  1. InternalTask.java不断从runnableQueue中取出Runnable并执行任务
package p126_thread_pool;

/**
 * @ClassName InternalTask
 * @Description TODO
 * 不断从runnableQueue中取出Runnable并执行任务
 * @Author Cays
 * @Date 2019/5/4 12:03
 * @Version 1.0
 **/
public class InternalTask implements Runnable {
    private final RunnableQueue runnableQueue;
    private volatile boolean running = true;

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

    @Override
    public void run() {
        //如果当前任务为running且没有被中断,则将其不断地从queue中获取runnable,然后执行run
        while (running && !Thread.currentThread().isInterrupted()){
            try {
                Runnable task = runnableQueue.take();
                task.run();
            }catch (InterruptedException e){
                running = false;
                break;
            }
        }
    }
    //停止当前任务,主要会在线程池的shutdown方法中使用
    public void stop(){
        this.running = false;
    }
}

  1. LinkedRunnableQueue.java双向循环链表实现线程任务队列RunnableQueue基本操作
package p126_thread_pool;

import java.util.LinkedList;

/**
 * @ClassName LinkedRunnableQueue
 * @Description TODO
 * LinkedRunnableQueue双向循环链表实现线程任务队列基本操作
 * @Author Cays
 * @Date 2019/5/4 12:11
 * @Version 1.0
 **/
public class LinkedRunnableQueue implements RunnableQueue {
    //任务队列的最大容量,在构造时传入
    private final int limit;
    //若任务队列中的任务已经满了,则需要执行拒绝策略
    private final DenyPolicy denyPolicy;
    //存放任务的队列
    private final LinkedList<Runnable> runnableList = new LinkedList<>();
    private final ThreadPool threadPool;

    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 {
                    //如果任务队列没有可执行任务,则当前线程会挂起,
                    //进入runnableList关联的monitor set中等待唤醒
                    runnableList.wait();
                }catch (InterruptedException e){
                    //被中断时将异常抛出
                    throw e;
                }
            }
            return runnableList.removeFirst();
        }
    }

    @Override
    public int size() {
        synchronized (runnableList){
            //返回当前任务队列的任务数
            return runnableList.size();
        }
    }
}

  1. RunnableDenyException.java错误抛出
package p126_thread_pool;

/**
 * @ClassName RunnableDenyException
 * @Description TODO
 * RunnableDenyException是RuntimeException的子类,主要通知人物提交者,任务队列
 * 无法再接收新的任务
 * @Author Cays
 * @Date 2019/5/4 12:00
 * @Version 1.0
 **/
public class RunnableDenyException extends RuntimeException {
    public RunnableDenyException(String message){
        super(message);
    }
}

  1. BasicThreadPool.java实现ThreadPool
package p126_thread_pool;

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

/**
 * @ClassName BasicThreadPool
 * @Description TODO
 * 线程池的初始化:
 * 数量控制属性、创建线程工厂、任务队列策略等功能
 * @Author Cays
 * @Date 2019/5/4 12:31
 * @Version 1.0
 **/
public class BasicThreadPool extends Thread implements ThreadPool {
    //初始化线程数量
    private final int initSize;
    //线程池最大线程数量
    private final int maxSize;
    //线程池核心线程数量
    private final int coreSize;
    //当前活跃的线程数量
    private int activeCount;
    //创建线程所需的工厂
    private final ThreadFactory threadFactory;
    //任务队列
    private final RunnableQueue runnableQueue;
    //线程池是否已经被shutdown
    private volatile boolean isShutdown = false;
    //工作线程队列
    private final Queue<ThreadTask> threadQueue = new ArrayDeque<>();
    private static final DenyPolicy DEFAULT_DENY_POLICY = new DenyPolicy.DiscardDenyPolicy();
    private static final ThreadFactory DEFAULT_THREAD_FACTORY = new DefaultThreadFactory();
    private final long keepAliveTime;
    private final TimeUnit timeUnit;
    //构造线程时传参
    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();
    }
    //初始化时,先创建initSize个线程
    private void init(){
        start();
        for (int i = 0; i < initSize; i++){
            newThread();
        }
    }
    @Override
    public void execute(Runnable runnable) {
        if (this.isShutdown){
            throw new IllegalStateException("The thread pool is destroy");
        }
        //提交任务只是简单第往任务队列中插入Runnable
        this.runnableQueue.offer(runnable);
    }
    private void newThread(){
        //创建任务线程并且启动
        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();
        threadTask.internalTask.stop();
        this.activeCount--;
    }

    @Override
    public void run() {
        //run方法继承自Thread,主要用于维护线程数量,比如扩容,回收
        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;
                }
                //当前队列中有任务尚未处理,并且activeCount<maxSize则继续扩容
                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 shutdown() {
        synchronized (this){
            if (isShutdown)return;
            isShutdown=true;
            threadQueue.forEach(threadTask -> {
                threadTask.internalTask.stop();
                threadTask.thread.interrupt();
            });
            this.interrupt();
        }
    }

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

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

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

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

    @Override
    public int getActiveCount() {
        if (isShutdown)
            throw new IllegalStateException("The thread pool is destroy");
        return this.activeCount;
    }

    @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;
        }
    }
    private static class DefaultThreadFactory implements ThreadFactory{
        private static final AtomicInteger group_counter=new AtomicInteger(1);
        private static final ThreadGroup group =
                new ThreadGroup("myGroup-"+group_counter.getAndDecrement());
        public static final AtomicInteger COUNTER =new AtomicInteger(0);
        @Override
        public Thread createThread(Runnable runnable) {
            return new Thread(group,runnable,"thread-poll-"+COUNTER.getAndDecrement());
        }
    }
}

  1. ThreadPoolTest.java测试线程池
package p126_thread_pool;

import java.util.concurrent.TimeUnit;

/**
 * @ClassName ThreadPoolTest
 * @Description TODO
 * 线程池的应用
 * 将写一个简单的程序分别测试线程池的任务提交、线程池线程数量的动态扩展,
 * 以及线程池的销毁功能,代码如下所示。
 * @Author Cays
 * @Date 2019/5/4 13:31
 * @Version 1.0
 **/
public class ThreadPoolTest {
    public static void main(String[] args) throws InterruptedException {
        //定义线程池,初始化程数为2,核心或程数为4,最大程数为6.任务队列最多允许1000个任务
        final ThreadPool threadPool=new BasicThreadPool(2,6,4,1000);
        //定义20个任务并且提交蛤线程池
        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();
                }
            });
        }
        for (; ; ){
            //不断输出线程池的信息
            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("==========================================");
            TimeUnit.SECONDS.sleep(5);
        }
    }
}

  1. 运行结果
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值