线程池剖析(一)

我们借用JDK自带的线程池ThreadPoolExecutor讲解线程池思想,打算分三个主题来讲:

  1. corePoolSize、maximumPoolSize与workQueue
  2. ThreadFactory
  3. RejectedExecutionHandler

本文先讲第一个主题。

1、corePoolSize、maximumPoolSize与workQueue

线程池的运行过程:
在这里插入图片描述

为了方便测试的时候,了解线程的调用情况,因此改写了ThreadFactory,线程名称前缀为THREAD-POOL-,按序号递增,这样我们就能清楚看到线程调用的是核心线程还是拓展线程。由于JDK线程池是先创建核心线程,后面有需要再创建拓展线程,因此index <= corePoolSize的都是为核心线程,其他的则为拓展线程

public class AsyncThreadFactory implements ThreadFactory {

    private final AtomicInteger index = new AtomicInteger(1);

    @Override
    public Thread newThread(Runnable r) {
        return new Thread(r, String.format("THREAD-POOL-%s", index.getAndIncrement()));
    }
}

测试代码:

public class AsyncUtilMain {

    /**
     * 核心线程数
     */
    private static final int CORE_POOL_SIZE = 10;
    /**
     * 最大线程数
     */
    private static final int MAX_POOL_SIZE = 100;
    /**
     * 阻塞队列长度
     */
    private static final int QUEUE_SIZE = 10;
    /**
     * 需求线程数
     */
    private static final int REQUIREMENT_POOL_SIZE = 10;


    public static void main(String[] args) {
        
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, 60, TimeUnit.MINUTES, new LinkedBlockingQueue<>(QUEUE_SIZE),
                new AsyncThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

        for (int index = 0; index < REQUIREMENT_POOL_SIZE; index++) {
            int value = index;
            threadPoolExecutor.submit(() -> System.out.println(Thread.currentThread().getName() + ":" + value));
        }

        threadPoolExecutor.shutdown();
    }
}

根据上述流程图,线程池的运行情况会有以下四种:

1、corePoolSize >= 需求线程数

10个核心线程数, 90个可拓展线程数, 阻塞队列数10个
需求线程数为10个, 因此所有的线程均可被核心线程数调用
所以运行结果应该为1~10号线程(核心线程)完成整个过程
运行结果:

THREAD-POOL-2:1
THREAD-POOL-4:3
THREAD-POOL-3:2
THREAD-POOL-1:0
THREAD-POOL-5:4
THREAD-POOL-6:5
THREAD-POOL-7:6
THREAD-POOL-8:7
THREAD-POOL-9:8
THREAD-POOL-10:9

2、corePoolSize + workQueueSize >= 需求线程数

5个核心线程数, 5个可拓展线程数, 阻塞队列长度为5
需求线程数为10个, 因此5个核心线程会马上消费5个需求线程,剩下的5个会在阻塞队列中等待5个核心线程消费。
所以运行结果应该为1~5号线程(核心线程)完成整个过程
配置代码:

    /**
     * 核心线程数
     */
    private static final int CORE_POOL_SIZE = 5;
    /**
     * 最大线程数
     */
    private static final int MAX_POOL_SIZE = 10;
    /**
     * 阻塞队列长度
     */
    private static final int QUEUE_SIZE = 5;
    /**
     * 需求线程数
     */
    private static final int REQUIREMENT_POOL_SIZE = 10;

运行结果:

THREAD-POOL-3:2
THREAD-POOL-4:3
THREAD-POOL-1:0
THREAD-POOL-2:1
THREAD-POOL-1:7
THREAD-POOL-4:6
THREAD-POOL-5:4
THREAD-POOL-3:5
THREAD-POOL-1:9
THREAD-POOL-2:8

3、corePoolSize + workQueueSize < 需求线程数

5个核心线程数, 5个可拓展线程数, 阻塞队列长度为3
需求线程数为10个, 因此5个核心线程会马上消费5个需求线程,剩下的3个会在阻塞由于阻塞队列溢出,那么剩下的两个需求线程将会触发可拓展线程,因此实际运行的线程应该为1~5号线程(核心线程)和 6 ~ 7号线程(可拓展线程)

配置代码:

    /**
     * 核心线程数
     */
    private static final int CORE_POOL_SIZE = 5;
    /**
     * 最大线程数
     */
    private static final int MAX_POOL_SIZE = 10;
    /**
     * 阻塞队列长度
     */
    private static final int QUEUE_SIZE = 3;
    /**
     * 需求线程数
     */
    private static final int REQUIREMENT_POOL_SIZE = 10;

运行结果:

THREAD-POOL-1:0
THREAD-POOL-6:8
THREAD-POOL-1:5
THREAD-POOL-6:6
THREAD-POOL-5:4
THREAD-POOL-2:1
THREAD-POOL-4:3
THREAD-POOL-7:9
THREAD-POOL-3:2
THREAD-POOL-1:7

4、maximumPoolSize+ workQueueSize + < 需求线程数

这种情况是最大线程数和阻塞队列都不足以满足需求线程数,那么这时就会触发线程池配置的拒绝策略:

配置代码:

/**
     * 核心线程数
     */
    private static final int CORE_POOL_SIZE = 5;
    /**
     * 最大线程数
     */
    private static final int MAX_POOL_SIZE = 10;
    /**
     * 阻塞队列长度
     */
    private static final int QUEUE_SIZE = 3;
    /**
     * 需求线程数
     */
    private static final int REQUIREMENT_POOL_SIZE = 15;

运行结果:

THREAD-POOL-10:12
THREAD-POOL-5:4
THREAD-POOL-4:3
Exception in thread “main” THREAD-POOL-5:5
THREAD-POOL-6:8
THREAD-POOL-7:9
THREAD-POOL-9:11
THREAD-POOL-8:10
THREAD-POOL-2:1
THREAD-POOL-10:7
THREAD-POOL-4:6
THREAD-POOL-1:0
THREAD-POOL-3:2
java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@4e50df2e rejected from java.util.concurrent.ThreadPoolExecutor@1d81eb93[Running, pool size = 10, active threads = 8, queued tasks = 1, completed tasks = 2]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
at cn.gaaidou.web.server.socket.AsyncUtilMain.main(AsyncUtilMain.java:40)

由于代码配置的拒绝策略是ThreadPoolExecutor.AbortPolicy,因此线程池直接抛出异常。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值