• 线程池创建与使用


    一、线程池优点

    (1)降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
    (2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
    (3)提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

    二、线程池状态

    ThreadPoolExecutor使用一个int正整数的高3位来表示线程池状态,低29位表示线程数量
    状态:
    running、shutsown、stop、tidying、terminated
    在这里插入图片描述
    为什么用一个整数保存?
    这些信息存储在一个原子变量ctl中,目的是将线程池状态与线程个数合二为一,这样就可以用一次cas原子操作进行赋值

    赋值:
    在这里插入图片描述

    三、构造方法

    corePoolSize核心线程数目(最多保留的线程数)
    maximumPoolSize线程池中最大线程数目
    keepAliveTime生存时间-针对救急线程
    unit时间单位-针对救急线程
    workQueue阻塞队列
    threadFactory线程工厂-可以为线程创建时起个好名字 handler拒绝策略

    核心线程数+救急线程数=最大线程数
    核心线程数 最大线程数分别对应1 2 参数

    线程池工作过程
    在这里插入图片描述
    c=2 核心线程是2 m=3 最大线程是3 所以救急线程是1
    阻塞队列 size=2

    过程:
    任务1到来核心线程1 创建并执行
    任务2到来核心线程2 创建并执行
    任务3到来 放进阻塞队列
    任务4到来 放到阻塞队列
    任务5到来 创建救急线程并且执行
    任务6到来 执行拒绝策略
    救急线程执行完任务后,生命周期到了就自动销毁
    而核心线程执行完之后,会保留在线程池中,一直存在不会销毁

    keepAliveTime、unit 这两个参数控制救急线程的生存时间

    救急线程:
    如果队列选择了有界队列,那么任务超过了队列大小时,会创建maximumPoolSize - corePoolSize数目的救急线程

    拒绝策略:
    JDK提供的四种拒绝策略
    在这里插入图片描述

    四、创建线程池

    Executors已经为我们封装好了 4 种常见的功能线程池
    newFixedThreadPool
    在这里插入图片描述
    **核心线程数==最大线程数(**没有救急线程被创建),因此也无需超时时间
    阻塞队列是无界的,可以放任意数量的任务

    评价:使用于任务量已知,相对耗时的任务

    public class TestThreadPoolExecutors {
        public static void main(String[] args) {
            ExecutorService pool = Executors.newFixedThreadPool(2);
            pool.execute(()->{
                System.out.println(Thread.currentThread().getName()+":1");
            });
            pool.execute(()->{
                System.out.println(Thread.currentThread().getName()+":2");
            });
            pool.execute(()->{
                System.out.println(Thread.currentThread().getName()+":3");
            });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    newCachedThreadPool
    在这里插入图片描述

    核心线程数是0, 最大线程数是Integer.MAX_ _VALUE, 救急线程的空闲生存时间是60s, 意味着全部都是救急线程(60s后可以回收)
    救急线程可以无限创建
    队列采用了SynchronousQueue 实现特点是,它没有容量,没有线程来取是放不进去的(- 手交钱、一手交货)

    特点:
    整个线程池表现为线程数会根据任务量不断增长,没有上限,当任务执行完毕,空闲1分钟后释放线程

    评价:
    适合任务数比较密集,但每个任务执行时间较短的情况

    newSingleThread Executor
    在这里插入图片描述

    使用场景
    希望多个任务排队执行。线程数固定为1,任务数多于1时,会放入无界队列排队。任务执行完毕,这唯一的线程也不会被释放

    区别:
    自己创建一个单线程串行执行任务,如果任务执行失败而终止那么没有任何补救措施,而线程池还会新建-个线程,保证池的正常工作

    Executors.newSingleThreadExecutor()线程个数始终为1,不能修改
    FinalizableDelegatedExecutorService 应用的是装饰器模式,只对外暴露了ExecutorService 接口,因此不能调用ThreadPoolExecutor中特有的方法

    Executors.newFixedThreadPool(1)初始时为1,以后还可以修改,对外暴露的是ThreadPoolExecutor对象,可以强转后调用setCorePoolSize等方法进行修改

    五、提交任务

    //执行任务
    void execute(Runnable command);

    //可以获得任务执行结果
    Future submit(Callable task);
    例:
    在这里插入图片描述

    六、关闭线程池

    shutdown
    线程池状态变为SHUTDOWN
    不会接收新任务
    但已提交的(队列中)任务会执行完
    不会中断正在执行的任务

    此方法不会阻塞调用线程的执行

    shutdownNow
    线程池状态变为STOP
    不会接收新任务
    会将队列中的任务作为方法的返回结果.
    中断正在执行的任务

    并用interrupt 的方式中断正在执行的任务

    其实 Executors 的 4 个功能线程有如下弊端:

    FixedThreadPool 和 SingleThreadExecutor:主要问题是堆积的请求处理队列均采用 LinkedBlockingQueue,可能会耗费非常大的内存,甚至 OOM。
    CachedThreadPool 和 ScheduledThreadPool:主要问题是线程数最大数是 Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至 OOM。

  • 相关阅读:
    flutter dio^5.3.3实现刷新token
    1.19.5.4.流上的Join、常规Join、时间区间Join、时态表Join、基于处理时间的时态Join、时态表函数Join、用法
    提升写作效率:ChatGPT助力学术论文撰写
    STM32移植LVGL8.2
    充气膜结构的应用领域
    所有字母异位词
    vim程序编辑器
    【leetcode】排序数组中两个数字之和
    USB Network Native Driver for ESXi更新支持ESXi8.0
    Ubuntu 22.04 搭建 KubeSphere 3.4.1 集群
  • 原文地址:https://blog.csdn.net/weixin_45511599/article/details/125889085