线程池

作者: sizuoyi00 | 来源:发表于2019-12-03 00:40 被阅读0次

使用场景

执行时间短,需要处理的任务量比较大

优势
1.重用线程,创建(用户空间->内核空间->内核线程)的销毁线程的开销,提高性能
2.提高响应速度,因为不需要创建
3.统一管理,对线程进行一些维护和管理,比如定时开始,周期执行,并发数控制等等

ThreadPoolExecutor

构造方法
    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.acc = System.getSecurityManager() == null ? null : AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }
核心参数说明
  • corePoolSize
    核心线程数,默认情况下核心线程会一直存活,即使处于闲置状态也不会受存keepAliveTime限制,除非将allowCoreThreadTimeOut设置为true。
    提交任务时,当运行的线程数小于corePoolSize时,将创建一个新线程来处理请求,即使其他工作线程是空闲的。
  • maximumPoolSize
    线程池所能容纳的最大线程数,如果有多于corePoolSize但小于maximumPoolSize的线程在运行,则只有在队列满时才会创建新线程。通过将corePoolSize和maximumPoolSize设置为相同的值,可以创建一个固定大小的线程池。
  • keepAliveTime
    非核心线程的闲置超时时间,超过这个时间就会被回收。核心线程不受此控制,除非将allowCoreThreadTimeOut设置为true。
  • unit
    指定keepAliveTime的单位,如TimeUnit.SECONDS。
  • workQueue
    线程池中的任务队列,核心线程数满了后添加到任务队列。
    常用的有三种队列:参考阻塞队列文章
    LinkedBlockingDeque:指定大小代表定长队列,不指定相当于无界队列。
    ArrayBlockingQueue:定长队列。
    SynchronousQueue:无缓存队列,不存储元素。
  • threadFactory
    线程创建工厂,提供创建新线程的功能,接口中只有newThread(Runnable r)方法
  • handler
    拒绝策略,当线程池资源不足(核心线程数,任务队列,最大线程数都占满),采用拒绝策略。常见拒绝策略:
    ThreadPoolExecutor.AbortPolicy:默认拒绝策略,丢弃任务并抛错处理
    ThreadPoolExecutor.CallerRunsPolicy:由调用者线程执行该任务,如果执行器已经关闭则丢弃任务。
    ThreadPoolExecutor.DiscardPolicy:丢弃任务,不执行任何操作。
    ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任,重新尝试执行任务,如果执行器已经关闭则丢弃任务。

Executors创建线程池(禁用)

  • newSingleThreadExecutor
    单线程线程池,无界队列,出现异常则重新创建一个代替。
    new ThreadPoolExecutor(1, 1, 0L,TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())
  • newFixedThreadPool
    固定大小线程池,无界队列,出现异常则会补充一个新线程。
    new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())
  • newCachedThreadPool
    可缓存线程池,SynchronousQueue无缓冲队列,如果没有可用的现有线程,将创建一个新的线程并将其添加到池中。已经60秒没有使用的线程将被终止并从缓存中删除。因此,长时间保持空闲的池不会消耗任何资源。
    new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>())
阿里巴巴编程规范对于线程池的要求

线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors 返回的线程池对象的弊端如下:
1)FixedThreadPool 和 SingleThreadPool: 允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool: 允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

线程池状态分析

  • running:能够接收新任务,并且对已添加任务进行处理。
    线程池初始化状态,线程一创建状态为running,初始线程数任务数为0
  • shutdown:不接收新任务,可以对已添加任务进行处理。
    调用线程池shutdown()方法running->shutdown
  • stop:不可以添加新任务,不处理已添加任务,正在处理的任务中止操作。
    调用线程池shutdownNow()方法,running/shutdown->stop
  • tidying:所有任务已终止,ctl记录的任务数量为0,当线程池状态为tidying时,会调用钩子函数terminated()。
    shutdown状态阻塞队列为空,并且线程中执行的任务为空,转为tidying。
    stop状态,线程中执行的任务为空,转为tidying。
  • termined:线程池彻底终止。
    tidying状态,执行完terminated()后,转为terminated状态
    任务数指的是线程数

执行规则:核心线程>阻塞队列>非核心线程>拒绝策略

  • 如果任务队列为无界队列
    线程数<核心线程数:创建核心线程
    核心线程数<线程数<最大线程数:加入队列
    线程数>最大线程数:加入队列
    无界队列,创建核心线程->队列
  • 如果任务队列为有界队列
    线程数<核心线程数:创建核心线程
    核心线程数<线程数<最大线程数:加入队列,队列满后,创建非核心线程
    线程数>最大线程数:队列未满,加入队列;队列满后,拒绝策略
    有界队列,创建核心线程->队列->创建非核心线程
    任务完成后,闲置时间达到超时时间后,非核心线程会被清除
  • 如果任务队列为无缓存队列SynchronousQueue
    线程数<核心线程数:创建核心线程
    核心线程数<线程数<最大线程数:创建非核心线程
    线程数>最大线程数:拒绝策略
    无缓存队列,创建核心线程->创建非核心线程
    任务完成后,闲置时间达到超时时间后,非核心线程会被清除

非核心线程也可以执行阻塞队列的任务

实例demo可参考:
https://blog.csdn.net/qq_25806863/article/details/71126867

相关文章

  • java线程池

    线程VS线程池 普通线程使用 创建线程池 执行任务 执行完毕,释放线程对象 线程池 创建线程池 拿线程池线程去执行...

  • java----线程池

    什么是线程池 为什么要使用线程池 线程池的处理逻辑 如何使用线程池 如何合理配置线程池的大小 结语 什么是线程池 ...

  • Java线程池的使用

    线程类型: 固定线程 cached线程 定时线程 固定线程池使用 cache线程池使用 定时调度线程池使用

  • Spring Boot之ThreadPoolTaskExecut

    初始化线程池 corePoolSize 线程池维护线程的最少数量keepAliveSeconds 线程池维护线程...

  • 线程池

    1.线程池简介 1.1 线程池的概念 线程池就是首先创建一些线程,它们的集合称为线程池。使用线程池可以很好地提高性...

  • 多线程juc线程池

    java_basic juc线程池 创建线程池 handler是线程池拒绝策略 排队策略 线程池状态 RUNNIN...

  • ThreadPoolExecutor线程池原理以及源码分析

    线程池流程: 线程池核心类:ThreadPoolExecutor:普通的线程池ScheduledThreadPoo...

  • 线程池

    线程池 [TOC] 线程池概述 什么是线程池 为什么使用线程池 线程池的优势第一:降低资源消耗。通过重复利用已创建...

  • java 线程池使用和详解

    线程池的使用 构造方法 corePoolSize:线程池维护线程的最少数量 maximumPoolSize:线程池...

  • 线程池

    JDK线程池 为什么要用线程池 线程池为什么这么设计 线程池原理 核心线程是否能被回收 如何回收空闲线程 Tomc...

网友评论

      本文标题:线程池

      本文链接:https://www.haomeiwen.com/subject/kkeuwctx.html