1. 线程池简介

介绍

当程序中需要使用异步或提高效率的时候我们需要使用到线程池。

ThreadPoolExecutor

构造参数介绍

 /**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * @param unit the time unit for the {@code keepAliveTime} argument
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * @param threadFactory the factory to use when the executor
     *        creates a new thread
     * @param handler the handler to use when execution is blocked
     *        because the thread bounds and queue capacities are reached
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code threadFactory} or {@code handler} is null
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) 
  1. corePoolSize 核心线程数
  2. maximumPoolSize 最大线程数
  3. keepAliveTime 保持存活时间
  4. unit 保持存活时间单位
  5. workQueue 任务存储队列
  6. threadFactory 线程工厂
  7. handler 拒绝策略

corePoolSize

核心线程数,线程池在被创建后是没有线程的,当一个任务被丢进线程池时,如果线程池的任务数量没有超过核心线程数,那么会创建一个线程work计算当前任务

maximumPoolSize

最大线程数,当一个任务被丢进线程池时,如果核心线程数满了,并且任务队列也满了,并且maximumPoolSize>corePoolSize,那么会创建一个 work 计算当前任务

keepAliveTime,unit

unit是keepAliveTime的时间单位,当线程池中的线程数多与核心线程数(maximumPoolSize-corePoolSize这部分线程),并且这部分线程一直处于等待状态,那么当等待时长超过keepAliveTime这部分线程会被回收

workQueue

任务存储队列,当一个任务被丢进线程池时,如果核心线程数满了并且任务队列没有满,那么这个task会丢进任务队列中等待被计算。

threadFactory

线程工厂,用来生产线程的工厂。一般使用默认的线程池工厂Executors.defaultThreadFactory(),默认的线程池工厂都是在同一个线程组,拥有同样的优先级并且都是守护线程

handler

拒绝策略,当核心线程数满了,并且任务队列也满了,并且最大线程数也满了,这个时候如果在来一个task,那么会执行拒绝策略

拒绝策略
AbortPolicy

抛异常

 /**
     * A handler for rejected tasks that throws a
     * {@code RejectedExecutionException}.
     */
    public static class AbortPolicy implements RejectedExecutionHandler {
        /**
         * Creates an {@code AbortPolicy}.
         */
        public AbortPolicy() { }

        /**
         * Always throws RejectedExecutionException.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         * @throws RejectedExecutionException always
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }
CallerRunsPolicy

如果线程池没有被暂停,那么就使用当前线程(往线程池中丢任务的线程)执行

/**
     * A handler for rejected tasks that runs the rejected task
     * directly in the calling thread of the {@code execute} method,
     * unless the executor has been shut down, in which case the task
     * is discarded.
     */
    public static class CallerRunsPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code CallerRunsPolicy}.
         */
        public CallerRunsPolicy() { }

        /**
         * Executes task r in the caller's thread, unless the executor
         * has been shut down, in which case the task is discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }
DiscardPolicy

丢弃策略,执行将当前任务丢弃

 /**
     * A handler for rejected tasks that silently discards the
     * rejected task.
     */
    public static class DiscardPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardPolicy}.
         */
        public DiscardPolicy() { }

        /**
         * Does nothing, which has the effect of discarding task r.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }
DiscardOldestPolicy

当线程池没有被暂停的时候,会将任务队列Queue中弹出一个丢弃,并且将当前任务重新丢给线程池

/**
     * A handler for rejected tasks that discards the oldest unhandled
     * request and then retries {@code execute}, unless the executor
     * is shut down, in which case the task is discarded.
     */
    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardOldestPolicy} for the given executor.
         */
        public DiscardOldestPolicy() { }

        /**
         * Obtains and ignores the next task that the executor
         * would otherwise execute, if one is immediately available,
         * and then retries execution of task r, unless the executor
         * is shut down, in which case task r is instead discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }

添加任务的流程图

添加任务的流程图

coding

代码如下
package pres.bik.lean.concurrent;

import java.util.concurrent.*;

/**
 * 线程池参数
 *
 * @author yangkaifei
 * @version 1.0
 * @date 2021/11/28 4:52 下午
 */
public class ThreadPoolExecutorLean {

    /**
     * 核心线程数
     */
    private static int CORE_POOL_SIZE = 2;
    /**
     * 最大线程数
     */
    private static int MAXIMUM_POOL_SIZE = 3;

    /**
     * 存活时间
     */
    private static long KEEP_ALIVE_TIME = 60;

    /**
     * 队列大小
     */
    private static int WORK_QUEUE_SIZE = 2;

    /**
     * 任务存储队列
     */
    private static BlockingQueue<Runnable> WORK_QUEUE = new ArrayBlockingQueue<>(WORK_QUEUE_SIZE);

    /**
     * 抛异常策略
     */
    private static RejectedExecutionHandler HANDLER = new ThreadPoolExecutor.AbortPolicy();
    /**
     * 线程池
     */
    private static ThreadPoolExecutor EXECUTOR_SERVICE = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
            KEEP_ALIVE_TIME, TimeUnit.SECONDS, WORK_QUEUE, Executors.defaultThreadFactory(), HANDLER);

    public static void main(String[] args) {
        run();
    }

    /**
     * 线程池参数了解
     */
    private static void run() {
        int length = MAXIMUM_POOL_SIZE + WORK_QUEUE_SIZE + 2;
        for (int i = 1; i < length; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println("睡眠被中断");
            }
            int finalI = i;
            try {
                EXECUTOR_SERVICE.execute(new Thread(() -> {
                    System.out.println("============");
                    System.out.println(String.format("开始执行任务:%s", finalI));
                    System.out.println(String.format("任务%s活跃线程数:%s", finalI, EXECUTOR_SERVICE.getActiveCount()));
                    System.out.println(String.format("任务%s队列中的数量:%s", finalI, EXECUTOR_SERVICE.getQueue().size()));
                    System.out.println("============");
                    try {
                        Thread.sleep(20000);
                    } catch (InterruptedException e) {
                        System.out.println("睡眠被中断");
                    }
                }));
            } catch (Exception e) {
                System.err.println("执行了异常策略:" + finalI);
            }
        }
        EXECUTOR_SERVICE.shutdown();
    }
}

运行结果
============
开始执行任务:1
任务1活跃线程数:1
任务1队列中的数量:0
============
============
开始执行任务:2
任务2活跃线程数:2
任务2队列中的数量:0
============
============
开始执行任务:5
任务5活跃线程数:3
任务5队列中的数量:2
============
执行了异常策略:6
============
开始执行任务:3
任务3活跃线程数:3
任务3队列中的数量:1
============
============
开始执行任务:4
任务4活跃线程数:3
任务4队列中的数量:0
============
听我狡辩
1

执行结果:

============
开始执行任务:1
任务1活跃线程数:1
任务1队列中的数量:0
============

因为核心线程数为2,当执行第1个任务时核心线程数没有满,所以执行创建一个work执行当前线程

2

执行结果:

============
开始执行任务:2
任务2活跃线程数:2
任务2队列中的数量:0
============

因为核心线程数为2,当执行第2个任务时核心线程数没有满,所以执行创建一个work执行当前线程

3

执行结果:

============
开始执行任务:5
任务5活跃线程数:3
任务5队列中的数量:2
============

当执行第5个任务时,第3个、第4个任务被丢进了任务队列中,而当执行第5个的时候核心线程数满了,并且任务队列也满了(2+2-4)所以第五个任务直接创建了一个新的线程执行(maximumPoolSize)

4

执行结果:

执行了异常策略:6

因为执行第6个任务时,核心线程数满了,任务队列也满了,最大线程也满了,所以执行了丢弃策略(maximumPoolSize+queueSize=5)

5

执行结果:

============
开始执行任务:3
任务3活跃线程数:3
任务3队列中的数量:1
============

当执行第3个任务时,任务被丢到了任务队列,当有空闲的线程时,他才被执行。而执行它的时候任务队列数量从2变成1

6

执行结果:

============
开始执行任务:4
任务4活跃线程数:3
任务4队列中的数量:0
============

当执行第4个任务时,任务被丢到了任务队列,当有空闲的线程时,他才被执行。而执行它的时候任务队列数量从1变成0

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值