Java多线程高并发高级篇(一)--线程池核心详解

阅读更多

在说核心内容之前,需要问一个问题,既然单个线程的创建和销毁都很简单,我们为什么要使用线程池?

使用池化技术是为了什么?

估计工作过很多年的老鸟们对这些东西都能说出个一二三来,无非就是以下几点:

1、线程相对于进程而言,虽然是轻量级的,但是它的创建依然需要占用我们那点宝贵的内存资源。如果无限制的创建线程,对应垃圾回收而言也是很有压力的,毕竟线程也是对象。使用线程池统一进行线程的调度,便于管理和控制。

2、线程的创建和关闭是需要花费时间的,这点毋庸置疑吧。如果任务非常多,频繁的创建和销毁线程也是需要占用系统的分片时间的,对于系统而言,这点时间对于处理任务的时间来说,有点浪费。

总结一下,使用线程池的目的就是将系统创建的线程进行复用,节约创建和销毁线程带来的时间开销。使用线程池后,创建线程就变成了从线程池获取空闲线程(当然,没有线程的时候也是需要创建的),销毁线程就变成了将线程归还线程池。

创建线程是为了什么?当然是为了处理任务(Task)。

Java多线程高并发高级篇(一)--线程池核心详解_第1张图片
 

 

一、JDK对线程池的支持

JDK提供了一套Executor框架,帮助开发人员有效的进行线程控制。

Executor框架结构图(最好自己画个UML类图,首先需要知道类图中每个符号的意思,这是源码必备的分析方法):


Java多线程高并发高级篇(一)--线程池核心详解_第2张图片
以上涉及到的核心成员类都在java.util.concurrent包下。

上图是全部的UML类图关系,猛然一看,估计你不懵都难。所以,我们抛去依赖关系,得到最简图,这样理解起来就不费劲了。


Java多线程高并发高级篇(一)--线程池核心详解_第3张图片
 那么,我们说的线程池是谁?就是ThreadPoolExecutor。我学习东西喜欢刨根问底,所以,我想问为什么它就是线程池?我们看上图,所有接口的第一个实现类是谁(不算抽象类)?对头,就是ThreadPoolExecutor。ScheduledThreadPoolExecutor扩展了线程池的功能(为什么英文起名字要见名知意,你从Scheduled是不是明白了什么),可以把它作为扩展功能了解。

以上整个代码架构,有人称之为Executor框架(不要一听框架就觉得有多么神奇高大,它就是个名字,因为线程池的一整套代码组织的起源是Executor,往上看下)。

 

二、线程池详解

既然要深究线程池,就不得不去看看源码,毕竟源码才是作者表达意思的代码体现。

我们看下线程池有些什么玩意--我们追踪了这个类中的实现,所有的构造函数,无一例外的都归结到下面最长的这个构造函数上,也就是说,这个构造函数是线程池的核心!



 

/**
     * Creates a new ThreadPoolExecutor with the given initial
     * parameters.
     *
     * @param corePoolSize the number of threads to keep in the
     * pool, even if they are idle.
     * @param maximumPoolSize the maximum number of threads to allow in the
     * pool.
     * @param keepAliveTime when the number of threads is greater than
     * the core, this is the maximum time that excess idle threads
     * will wait for new tasks before terminating.
     * @param unit the time unit for the keepAliveTime
     * argument.
     * @param workQueue the queue to use for holding tasks before they
     * are executed. This queue will hold only the Runnable
     * tasks submitted by the execute method.
     * @param threadFactory the factory to use when the executor
     * creates a new thread.
     * @param handler the handler to use when execution is blocked
     * because the thread bounds and queue capacities are reached.
     * @throws IllegalArgumentException if corePoolSize or
     * keepAliveTime less than zero, or if maximumPoolSize less than or
     * equal to zero, or if corePoolSize greater than maximumPoolSize.
     * @throws NullPointerException if workQueue
     * or threadFactory or handler are null.
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue 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.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

 

 

 我们详细解释下这些参数的含义:

看参数含义,我们最好不要自己去理解,看的时候要结合英文注释,因为注释部分是作者要表达的真正含义。

①corePoolSize: the number of threads to keep in the pool, even if they are idle.(核心线程池大小:为什么这么起名称,是因为作者想表达的含义是线程池应该保证线程数目会有这么多,不管他们创建以后是不是空闲)。

②maximumPoolSize: the maximum number of threads to allow in the pool.(线程池中允许创建线程的最大数目,啥意思?如果核心线程数已经达到,任务还源源不断的来,那么maximumPoolSize表达的意思就是核心线程数+新创建的线程数据<=最大线程数目)。

③keepAliveTime:when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.(超过核心线程数的线程,在新任务到来之前能存活的最长时间,如果没等到,那么它就拜拜了)

④unit: the time unit for the keepAliveTime argument.(就是keepAliveTime 参数的单位)

⑤BlockingQueue workQueue:the queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method.(等待执行的任务队列,它的作用就是用来存放还没有被执行的任务。这个队列仅仅用来存放被execute方法提交的Runnable任务,不要翻译成工作队列,那是给自己找麻烦)

⑥threadFactory:the factory to use when the executor creates a new thread.(线程工厂,用来创建新线程的工厂,一般使用默认工厂--Executors.defaultThreadFactory(),它是Executors类中的一个静态内部类的方法,返回一个实体类DefaultThreadFactory)

⑦RejectedExecutionHandler handler: the handler to use when execution is blocked because the thread bounds and queue capacities are reached.(当任务队列中任务已经达到了等待执行任务的队列的大小[有界队列会出现]时,要采取什么样的处理(handler)方式,取名叫拒绝策略,就是我应该怎么抛弃你)

 

下一篇,我们详细介绍下BlockingQueue 常用的等待执行任务存放的队列和RejectedExecutionHandler常用的任务拒绝策略。 

 

 

 

 

 

  • Java多线程高并发高级篇(一)--线程池核心详解_第4张图片
  • 大小: 180 KB
  • Java多线程高并发高级篇(一)--线程池核心详解_第5张图片
  • 大小: 1.2 MB
  • Java多线程高并发高级篇(一)--线程池核心详解_第6张图片
  • 大小: 74 KB
  • Java多线程高并发高级篇(一)--线程池核心详解_第7张图片
  • 大小: 25.1 KB
  • Java多线程高并发高级篇(一)--线程池核心详解_第8张图片
  • 大小: 46.2 KB
  • Java多线程高并发高级篇(一)--线程池核心详解_第9张图片
  • 大小: 82.7 KB
  • Java多线程高并发高级篇(一)--线程池核心详解_第10张图片
  • 大小: 30.5 KB
  • Java多线程高并发高级篇(一)--线程池核心详解_第11张图片
  • 大小: 59.8 KB
  • Java多线程高并发高级篇(一)--线程池核心详解_第12张图片
  • 大小: 9.5 KB
  • Java多线程高并发高级篇(一)--线程池核心详解_第13张图片
  • 大小: 128 KB
  • Java多线程高并发高级篇(一)--线程池核心详解_第14张图片
  • 大小: 113 KB
  • Java多线程高并发高级篇(一)--线程池核心详解_第15张图片
  • 大小: 170.3 KB
  • 查看图片附件

你可能感兴趣的:(线程池,多线程,线程)