基于ThreadPoolExecutor自定义线程池详解

在阿里巴巴开发手册中不建议使用 Executor:

因为默认的 Executors 线程池底层是基于 ThreadPoolExecutor 构造函数封装的,采用无界队列存放缓存任务,会无限缓存任务容易发生 内存溢出,会导致我们最大线程数会失效

线程池底层 ThreadPoolExecutor 实现原理

  1. 当线程数小于核心线程数时,创建线程。
  2. 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
  3. 当线程数大于等于核心线程数,且任务队列已满
    3.1 若线程数小于最大线程数,创建线程
    3.2 若线程数等于最大线程数,抛出异常,拒绝任务

 ThreadPoolExecutor 核心参数:

  1. corePoolSize:核心线程数量 一直正在保持运行的线程
  2. maximumPoolSize:最大线程数,线程池允许创建的最大线程数。
  3. keepAliveTime:超出 corePoolSize 后创建的线程的存活时间。
  4. unit:keepAliveTime 的时间单位。
  5. workQueue:任务队列,用于保存待执行的任务。
  6. threadFactory:线程池内部创建线程所用的工厂。
  7. handler:任务无法执行时的处理器

 线程池拒绝策略类型:

  1. AbortPolicy 丢弃任务,抛运行时异常
  2. CallerRunsPolicy 执行任务
  3. DiscardPolicy 忽视,什么都不会发生
  4. DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务
  5. 实现 RejectedExecutionHandler 接口,可自定义处理器(推荐)

 代码实现:

先创建自定义线程池拒绝策略类实现RejectedExecutionHandler

import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 实现 RejectedExecutionHandler 接口,可自定义处理器
 * 自定义线程池拒绝策略
 */
public class MyExecutionHandler implements ThreadFactory, RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.out.println(r.getClass()+":任务已满,自定义拒绝线程任务,阻塞3秒后重新放入队列");
//        r.run();//如果直接r.run()则由主线程main来执行该次溢出任务
        try {
            //此时队列满我们将阻塞3秒再将线程任务重新放回线程池中去
            Thread.sleep(3000L);
            executor.execute(r);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public Thread newThread(Runnable r) {
        return null;
    }
}

在创建自定义线程池:

import java.util.concurrent.*;

public class MyThreadPoolExecutor {
    public static ExecutorService newFixedThreadPool(int corePoolSize, int maximumPoolSize, int blockingQueue) {
/*        return new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
                60L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(blockingQueue), (RejectedExecutionHandler) new ThreadPoolExecutor.DiscardPolicy ());//拒绝策略为放弃任务*/
        return new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
                60L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(blockingQueue),(RejectedExecutionHandler)new MyExecutionHandler());
    }
}

这样我们自定义线程池就完成啦!然后测试下:

public class Test {
    public static void main(String[] args) throws InterruptedException {
        //1.提交的线程任务数<核心线程数  (核心线程数任务复用)
        //2.提交的线程任务数>核心线程数 且我们队列容量没有满 将该任务缓存到我们队列中
        // 循环3 4 5 6 7 缓存到我们队列中
        //3.提交的线程任务数>核心线程数 且我们队列容量满了
        //8,9,10
        // 最多在额外创建两个线程 4-2 2个线程
        // 2个线程 8 ,9
        // 10个任务----拒绝
        ExecutorService executorService =  MyThreadPoolExecutor.newFixedThreadPool(2,4,5);
        for (int i = 1; i <= 10; i++) {
            final int finalI = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "," + finalI);
                }
            });
        }
        Thread.sleep(1000L);
        //返回池中有史以来最大的线程数
        System.out.println(((ThreadPoolExecutor)executorService).getLargestPoolSize());
        // 实际上最多执行多少个任务 核心线程数+缓存队列的容量+最大线程数-核心线程数
    }
}

运行结果截图:

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值