• 线程池的理解


    一、线程池概念

    创建Java线程需要给线程分配堆栈内存以及初始化内存,还需要进行系统调用,频繁地创建和销毁线程会大大降低系统的运行效率,采用线程池来管理线程有以下好处:

    提升性能:线程池能独立负责线程的创建、维护和分配
    线程管理:每个Java线程池会保持一些基本的线程统计信息,对线程进行有效管理

    在这里插入图片描述

     java.util.concurrent.Executor:  负责线程的使用与调度的根接口
     		|--ExecutorService 子接口: 线程池的主要接口
     			|--ThreadPoolExecutor 线程池的实现类
     			|--ScheduledExecutorService 子接口: 负责线程的调度
     				|--SchediledThreadPoolExecutor: 继承ThreadPoolExecutor,实现ScheduledExecutorService
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. Executor接口
      异步任务的"执行者"接口, Executor提供了一个execute()来执行已经提交的Runnable执行目标实例. Executor是作为执行者的角色, 目的是提供一种将"任务提交者"和"任务执行者"分开的机制, 它只有一个函数式方法:
    public interface Executor {
        void execute(Runnable var1);
    }
    
    • 1
    • 2
    • 3
    1. ExecutorService
      ExecutorService接口继承自Executor, 它是异步任务的"执行者服务"接口, 对外提供异步任务的接受者服务. ExecutorService提供了接收"接收异步任务并转交给执行者"的方法.
    public interface ExecutorService extends Executor {
    
        /**
         * 关闭执行器, 主要有以下特点:
         * 1. 已经提交给该执行器的任务将会继续执行, 但是不再接受新任务的提交;
         * 2. 如果执行器已经关闭了, 则再次调用没有副作用.
         */
        void shutdown();
    
        /**
         * 立即关闭执行器, 主要有以下特点:
         * 1. 尝试停止所有正在执行的任务, 无法保证能够停止成功, 但会尽力尝试(例如, 通过 Thread.interrupt中断任务, 但是不响应中断的任务可能无法终止);
         * 2. 暂停处理已经提交但未执行的任务;
         *
         * @return 返回已经提交但未执行的任务列表
         */
        List<Runnable> shutdownNow();
    
        /**
         * 如果该执行器已经关闭, 则返回true.
         */
        boolean isShutdown();
    
        /**
         * 判断执行器是否已经【终止】.
         * 仅当执行器已关闭且所有任务都已经执行完成, 才返回true.
         * 注意: 除非首先调用 shutdown 或 shutdownNow, 否则该方法永远返回false.
         */
        boolean isTerminated();
    
        /**
         * 阻塞调用线程, 等待执行器到达【终止】状态.
         *
         * @return {@code true} 如果执行器最终到达终止状态, 则返回true; 否则返回false
         * @throws InterruptedException if interrupted while waiting
         */
        boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
    
        /**
         * 提交一个具有返回值的任务用于执行.
         * 注意: Future的get方法在成功完成时将会返回task的返回值.
         *
         * @param task 待提交的任务
         * @param   任务的返回值类型
         * @return 返回该任务的Future对象
         * @throws RejectedExecutionException 如果任务无法安排执行
         * @throws NullPointerException       if the task is null
         */
        <T> Future<T> submit(Callable<T> task);
    
        /**
         * 提交一个 Runnable 任务用于执行.
         * 注意: Future的get方法在成功完成时将会返回给定的结果(入参时指定).
         *
         * @param task   待提交的任务
         * @param result 返回的结果
         * @param     返回的结果类型
         * @return 返回该任务的Future对象
         * @throws RejectedExecutionException 如果任务无法安排执行
         * @throws NullPointerException       if the task is null
         */
        <T> Future<T> submit(Runnable task, T result);
    
        /**
         * 提交一个 Runnable 任务用于执行.
         * 注意: Future的get方法在成功完成时将会返回null.
         *
         * @param task 待提交的任务
         * @return 返回该任务的Future对象
         * @throws RejectedExecutionException 如果任务无法安排执行
         * @throws NullPointerException       if the task is null
         */
        Future<?> submit(Runnable task);
    
        /**
         * 执行给定集合中的所有任务, 当所有任务都执行完成后, 返回保持任务状态和结果的 Future 列表.
         * 
         * 注意: 该方法为同步方法. 返回列表中的所有元素的Future.isDone() 为 true.
         *
         * @param tasks 任务集合
         * @param    任务的返回结果类型
         * @return 任务的Future对象列表,列表顺序与集合中的迭代器所生成的顺序相同,
         * @throws InterruptedException       如果等待时发生中断, 会将所有未完成的任务取消.
         * @throws NullPointerException       任一任务为 null
         * @throws RejectedExecutionException 如果任一任务无法安排执行
         */
        <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;
    
        /**
         * 执行给定集合中的所有任务, 当所有任务都执行完成后或超时期满时(无论哪个首先发生), 返回保持任务状态和结果的 Future 列表.
         */
        <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;
    
        /**
         * 执行给定集合中的任务, 只有其中某个任务率先成功完成(未抛出异常), 则返回其结果.
         * 一旦正常或异常返回后, 则取消尚未完成的任务.
         */
        <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;
    
        /**
         * 执行给定集合中的任务, 如果在给定的超时期满前, 某个任务已成功完成(未抛出异常), 则返回其结果.
         * 一旦正常或异常返回后, 则取消尚未完成的任务.
         */
        <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    1. AbstractExecutorService
      AbstractExecutorService是一个抽象类, 它实现了ExecutorService接口.
      AbstractExecutorService存在的目的是为ExecutorService中的接口提供默认实现

    2. ThreadPoolExecutor *
      JDK所有线程池实现的父类, 它继承于AbstractExecutorService抽象类.
      ThreadPoolExecutor是JUC线程池的核心实现类. 线程的创建和终止需要很大的开销, 线程池中预先提供了指定数量的可重用线程, 所以使用线程池会节省系统资源, 并且每个线程池都维护了一些基础的数据统计, 方便线程的管理和监控.

    3. ScheduledExecutorService
      ScheduledExecutorService是一个接口, 它继承于ExecutorService. 它是一个可以完成“延时”和“周期性”任务的调度线程池接口, 其功能和Timer/TimerTask类似.
      [Timer]Java定时工具类

    4. ScheduledThreadPoolExecutor
      继承于ThreadPoolExecutor, 它提供了ScheduledExecutorService线程池接口中"延时执行"和"周期执行"等抽象调度方法的具体实现. 类似于Timer, 但是在高并发程序中, ScheduledThreadPoolExecutor的性能要优于Timer.

    5. Executors
      Executors是一个静态工厂类, 它通过静态工厂方法返回ExecutorService, ScheduledExecutorService等线程池示例对象, 这些静态工厂方法可以理解为一些快捷的创建线程池的方法.

    二、构造方法

    研究一个类,先从它的构造方法开始。ThreadPoolExecutor提供了4个有参构造方法:

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                 Executors.defaultThreadFactory(), defaultHandler);
    }
    
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                 threadFactory, defaultHandler);
    }
    
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                 Executors.defaultThreadFactory(), handler);
    }
    
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    corePoolSize(必需):核心线程数。即池中一直保持存活的线程数,即使这些线程处于空闲。但是将allowCoreThreadTimeOut参数设置为true后,核心线程处于空闲一段时间以上,也会被回收。
    maximumPoolSize(必需):池中允许的最大线程数。当核心线程全部繁忙且任务队列打满之后,线程池会临时追加线程,直到总线程数达到maximumPoolSize这个上限。
    keepAliveTime(必需):线程空闲超时时间。当非核心线程处于空闲状态的时间超过这个时间后,该线程将被回收。将allowCoreThreadTimeOut参数设置为true后,核心线程也会被回收。
    unit(必需):keepAliveTime参数的时间单位。有:TimeUnit.DAYS(天)、TimeUnit.HOURS(小时)、TimeUnit.MINUTES(分钟)、TimeUnit.SECONDS(秒)、TimeUnit.MILLISECONDS(毫秒)、TimeUnit.MICROSECONDS(微秒)、TimeUnit.NANOSECONDS(纳秒)
    workQueue(必需):任务队列,采用阻塞队列实现。当核心线程全部繁忙时,后续由execute方法提交的Runnable将存放在任务队列中,等待被线程处理。
    threadFactory(可选):线程工厂。指定线程池创建线程的方式。
    handler(可选):拒绝策略。当线程池中线程数达到maximumPoolSize且workQueue打满时,后续提交的任务将被拒绝,handler可以指定用什么方式拒绝任务。

    三、四种线程池拒绝策略

    任务进来时候,先执行判断,判断核心线程是否处于空闲状态,如果不是,核心线程就先执行任务,如果核心线程已满,则判断任务队列是否有地方存放该任务,如果有就将任务保存在任务队列中,等待执行,如果满了,在判断最大可容纳线程数,如果没有超出这个数量,就开创非核心线程执行任务,如果超出了,就调用handler实现拒绝策略。

    handler的拒绝策略有四种:

    第一种AbortPolicy 不执行新任务,直接抛出异常,提示线程已满
    第二种DisCardPolicy :不执行新任务,也不抛出异常
    第三种 DisCardOrdSetPolicy 将消息队列的第一个任务替换为当前新进来的任务执行
    第四种 CallerRunsPolicy 由调用线程处理该任务,如果任务被拒绝了,则由调用线程 (提交任务的线程)直接执行此任务

  • 相关阅读:
    Objective-C 基础教程第三章,面向对象编程基础知识
    数据同步,还看Canal
    球迷 如何在Linux纯命令行玩转谷歌浏览器,边看欧洲杯,边看足球宝贝
    换个角度入门 K8s
    新手下白对Latex下手啦!
    FaceBook 遭遇有史以来全球最大宕机
    威马汽车欲曲线上市:沈晖已提前持股并任职,销量垫底、员工降薪
    ubuntu 安装redis详细教程
    重装系统后新建文本文档打不开怎么办
    基于Locust实现MQTT协议服务的压测脚本
  • 原文地址:https://blog.csdn.net/weixin_45817985/article/details/126926937