线程池核心原理详解

  • Post author:
  • Post category:其他




为什么需要线程池

我们知道相比较进程而言,线程是操作系统调度的更细粒度的资源,如果通过大量手动创建、调用线程,显然线程资源的复用,线程如何更好管理等问题就出现了。所以能不能有一种机制

既能解决实现线程的复用,以及线程管理呢

,这就提出

线程池

的概念,类比还有像其他基于池化思想的:数据库连接池,Http连接池等



线程池创建多线程

通常使用

Executors

工具类创建一个线程池,该类提供多种类型线程池的创建方法,主要分析一下3种

   //创建一个包含指定线程数的线程池(单池多线程)
   public static ExecutorService newFixedThreadPool(int nThreads)
   
   //创建一个只包含一个工作线程的线程池(单池单线程)
   public static ExecutorService newSingleThreadExecutor()
   
   //创建一个能自动扩容的线程池
   public static ExecutorService newCachedThreadPool()

查看源码,这三个方法底层本质都是依赖

ThreadPoolExecutor

,所以自定义线程池的话,我们重点关注

ThreadPoolExecutor

类就行,并且在阿里巴巴手册也推荐使用

ThreadPoolExecutor

构建一个线程池,因为它更灵活,可读性更高,适用更多的需求场景。后面会深入理解

ThreadPoolExecutor

,来了解线程池的整个工作原理



ThreadPoolExecutor线程池工作原理

在这里插入图片描述

工作流程:


ThreadPoolExecutor执行execute方法分下面4种情况


1.如果当前运行的线程数小于corePool,直接创建新线程来执行提交的任务

2.如果当前运行的线程数大于或等于corePool,将任务加入阻塞队列

3.如果无法加入任务到阻塞队列(队列已满),创建新的线程来执行任务

4.如果创建的线程数超过了maximumPool,任务将被拒绝,调用RejectedExecutionHandler.rejectedExecution()方法


ThreadPoolExecutor核心参数分析

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

corePoolSize:核心线程数

maximumPool:线程池能够容纳的最大线程数

BlockingQueue:用来暂时保存任务的阻塞队列

keepAliveTime:空闲线程存活时间

unit:时间单位

ThreadFactory:线程工厂

RejectedExecutionHandler:拒绝策略,当任务队列已满并且达到最大线程数后,线程池会调用相应的拒绝策略,可以分为以下几种策略

  • AbortPolicy(默认):抛出RejectedExecutionException异常吗,程序终止
  • CallerRunsPolicy:不抛弃任务,交给原来的调用者调用
  • DiscardOldestPolicy:抛弃队列中排队最久的任务,然后将当前任务添加到队列,再次尝试提交
  • DiscardPolicy:默默丢弃任务,不予处理,不抛异常



版权声明:本文为qq_40553042原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。