线程池创建及运行流程

1.线程池机制

当我们的线程数量过大时,频繁的线程开启和关闭会消耗额外的资源。通过线程池,可以不用去频繁的开启和关闭线程。当有一个线程要开启时,通过线程池中的线程开启。这个线程运行完毕时,将线程归还给线程池,用于后来的线程使用。

通过execute() \ submit() 提交给线程池

在这里插入图片描述

2.创建线程池

2.1ThreadPoolExecutor线程池参数

我们通过 ThreadPoolExecutor 去创建一个线程池

先来看看 ThreadPoolExecutot 对象的参数

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler);
  • corePoolSize
    核心线程数,这些线程是不会被回收的,一直存在于线程池中

  • maximumPoolSize
    最大线程数,在超出和弦线程池时,在工作队列已满的情况下,会创建额外的线程,这些线程的数量由求最大线程数确定

  • keepAliveTime
    额外线程存留时间,当创建了超出核心线程数的线程,当这些线程执行完任务后,超出了这个时间,将会被回收

  • unit
    时间单位,线程池存留时间的时间单位

  • workQueue
    任务队列,超出核心线程数的线程,会被分配到任务队列中等待,直到有现成执行完,该线程获取到线程时出队。这些任务队列都是BlockingQueue 的实现类,BlockingQueue 是一个阻塞队列,当有一个线程正在入队或出队时,其他线程不想允许操作。确保了线程安全。
    线程池工厂,设线程池组,与线程池内的线程名前缀
    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • handler
    拒绝策略方法,线程数量超出最大线程数时执行拒绝策略。有以下四种拒绝策略:

    1. AbortPolicy

      丢弃当前线程,并抛出异常
      在这里插入图片描述

    2. DiscardPolicy
      丢弃当前线程,不抛出异常
      在这里插入图片描述

    3. DiscardOldestPolicy

      拿到一个最“老"的线程,用来执行当前县城任务。先检测线程池是否关闭,然后再获取线程,执行任务
      在这里插入图片描述

2.2ThreadPoolExecutor线程池创建

还可以通过 Executors 执行器自动的去创建线程池。在 Executors 类中定义了大量的创建线程池的模板方法。在以下举几个例子说明:

  1. Executors.newFixedThreadPool()
    创建固定核心线程数的线程池

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
    

​ 我们可以看到,通过一个int类型的参数,设置了核心线程数和最大线程数。

  1. Executors.newSingleThreadExecutor()

    创建只有一个线程数的线程池

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
    

​ 这个方法没有参数,在方法的内部固定了核心线程数和最大线程数为1

  1. Executors.newCachedThreadPool()
    动态创建线程的线程池

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    

​ 相对前几个来说,该方法创建的线程池是较为特殊的一个线程池,该线程池的核心线程数为0,最大线程数为 Integer.MAX_VALUE=2147483647。这个线程池没有 核心线程数,并且该任务队列也不会存储任务队列,会直接判断线程数是否超过最大线程数,去创建新的该线程。

  1. Executors.newScheduledThreadPool()
    用于需要定时任务调度和周期性任务执行的场景
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}

这个方法创建的是 ScheduledThreadPoolExecutor,为ThreadPoolExecutor的子类

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
}

3.线程池执行流程

在这里插入图片描述

线程池在工作时会根据设置的参数去做线程调度,共有以下步骤:

  1. 在向线程池提交任务时,判断是否存在空闲线程
    • 空闲线程存在,分配空闲线程,执行该线程
  2. 空闲线程不存在,判断已有线程是否超出设置的核心线程数
    • 核心线程数未超出,创建新的核心线程去执行该线程任务
  3. 已超出,判断任务队列是否已满
    • 任务队列未满,将该线程任务放入工作队列中等待,等有其他线程执行任务后,归还线程,工作队列中的任务依次出队,获取空闲线程,执行线程任务
  4. 任务队列满,判断是否超出最大线程数
    • 最大线程数未超出,创建非核心线程,执行线程任务,该线程执行完任务,空闲的时间超出指定时间后将被回收
  5. 已超出,执行拒绝策略

4.线程池状态

在源码描述中,线程池有五种状态,分别是RUNNING,SHUTDOWN,STOP,TIDYING,TERMINATED

在这里插入图片描述

  • RUNNING
    • 运行状态,允许新任务,并处理工作队列中的任务
    • 可调用 shutdown()方法,切换到关闭状态
    • 调用 shutdownNow()方法,切换到停止状态
  • SHUTDOWN
    • 关闭状态,不接受新任务,会继续处理工作队列红的任务
  • STOP
    • 停止状态,不接受新任务,也不处理工作队列中的任务,同时终端正在执行的任务
  • TIDYING
    • 整理状态,所有任务已经结束,工作队列中的任务数量为0
  • TERMINARTED
    • 终止状态,线程池彻底关闭
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值