JUC线程池(Executors)详解

发布于:2022-12-02 ⋅ 阅读:(290) ⋅ 点赞:(0)

什么是线程池?

内存中的一块空间,空间里存放着已经实例化好的线程对象.
当需要使用线程时直接从线程池中去取,当代码中线程执行结束或者销毁时,把线程重新放入线程池,而不是让它处于死亡状态.

优点

  1. 降低系统资源消耗。通过重用线程对象,降低因为新建和销毁线程产生的系统消耗。

  2. 提高系统响应速度。直接从内存中获取线程对象,比新建线程更快。

  3. 提供线程可管理性。通过对线程池中线程数量的限制,避免无限创建线程导致的内存溢出或CPU资源耗尽等问题。

缺点

默认情况下,无论是否需要使用线程对象,线程池中都有一些线程对象,也就是说会占用一定内存。

Executor关系图

在这里插入图片描述
自定义线程池

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) 
参数总结:
  1. corePoolSize: 核心线程数大小
  2. maximumPoolSize:最大线程数大小(线程池中一共存在多少个线程)
  3. keepAliveSize:线程最大空闲时间
  4. unit;时间单位
  5. workQueue:任务队列类型
  6. threadFactory:线程工厂
  7. handler:拒绝策略
创建线程总结:
  1. 当线程数小于核心线程数时,创建线程, 直到达到指定的核心线程数。

  2. 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列(指的是有存储空间的队列,SynchronousQueue没有存储空间)。

  3. 当线程数大于等于核心线程数,且任务队列已满 。

​ i. 若线程数小于最大线程数且最大线程数是非零,创建临时线程, 直到达到最大线程数 。
注意:
如果工作队列满了,.但是核心线程有空闲的线程时,那么核心线程就会利用起来,把队列的第一个任务交给核心线程去处理,新的任务去工作队列缓存,

​ ii. 线程数等于最大线程数,触发拒绝策略,抛出异常

handler线程池拒绝策略

只有当任务队列已满,且线程数量已经达到maximunPoolSize才会触发拒绝策略。

1.AbortPolicy:默认策略,新任务提交直接抛出RejectedExecutionException,由调用者捕获
2.DisCardPolicy:丢弃新的任务,且不抛出异常.
3.DisCardOldestPolicy:调用poll()方法丢弃队列头的任务,然后提交新的任务
4.CallerRunsPolicy:由调用该任务的线程处理,线程池不参与,只要线程池不关闭,该任务一直在调用者的线程中.

Executors

Executors可以帮助快速实例化特定类型的线程池对象, Executors属于一个工具类, 返回值都是ExecutorService接口的实现类, 底层都是调用ThreadPoolExecutor()

1 SingleThreadExecutor()
在这里插入图片描述

  1. 构造方法参数:
  2. corePoolSize和maximumPoolSize: 1
  3. keepAliveTime: 0秒
  4. unit: 微妙
  5. workQueue: LinkedBlockingQueue
  6. 效果总结:
    1. 它只会创建一条工作线程处理任务;
    2. 采用的阻塞队列为LinkedBlockingQueue, 底层为单向链表。

2.newFixedThreadPool(int)
在这里插入图片描述

  1. 构造方法参数:

    1. corePoolSize和maximumPoolSize: nTheads
    2. keepAliveTime: 0秒
    3. unit: 毫秒
    4. workQueue: LinkedBlockingQueue
  2. 效果总结:

    1. 它是一种固定大小的线程池;
    2. corePoolSize和maximunPoolSize都为用户设定的线程数量nThreads;
    3. keepAliveTime为0,意味着一旦有多余的空闲线程,就会被立即停止掉;但这里keepAliveTime无效;
    4. 阻塞队列采用了LinkedBlockingQueue, 底层为链表;
    5. 实际线程数量将永远维持在nThreads,因此maximumPoolSize和keepAliveTime将无效。

3.newCachedThreadPool():缓存线程池
在这里插入图片描述

  1. 构造方法参数:

    1. corePoolSize: 0
    2. maximumPoolSize: Integer的最大值
    3. keepAliveTime: 60秒
    4. unit: 秒
    5. workQueue:SynchronousQueue
  2. 效果总结:

    1. 它是一个可以无限扩大的线程池;

    2. 它比较适合处理执行时间比较小的任务;

    3. corePoolSize为0,maximumPoolSize为无限大,意味着线程数量可以无限大;

    4. keepAliveTime为60S,意味着线程空闲时间超过60S就会被杀死;

    5. 采用SynchronousQueue(同步队列)装等待的任务,这个阻塞队列没有存储空间,这意味着只要有请求到来,就必须要找到一条工作线程处理他,如果当前没有空闲的线程,那么就会再创建一条新的线程。

4.newScheduledThreadPool()
在这里插入图片描述

  1. 构造方法参数:

    1. corePoolSize: corePoolize
    2. maximumPoolSize: Integer的最大值
    3. keepAliveTime: 10L
    4. unit: 毫秒
    5. workQueue:DeplayedWorkQueue
  2. 效果总结:

    1. 它采用DelayQueue存储等待的任务

    2. 它会根据time的先后时间排序,若time相同则根据sequenceNumber排序;

    3. DelayQueue队列:

      底层使用数组实现, 初始容量为16, 超过16个任务, 数组扩容, 每次扩容为之前的1.5倍

    4. 工作线程会从DelayQueue取已经到期的任务去执行;

    5. 执行后也可以将任务重新定时, 放入队列中;

    6. 支持定时, 周期性执行。

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到