线程池的概念

        线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。

线程池的优势

        (1) 降低系统资源消耗,通过重用现有的线程,降低创建和销毁线程的性能损耗。

        (2) 方便管控线程并发数,如果线程数量无限制的增长,会导致内存占满而出现OOM。

        (3) 提供了更加强大的功能。

线程池的主要参数

        corePoolSize:核心线程数。当现有线程数小于corePoolSize,即便此时存在空闲线程,也会通过创建一个新线程来执行任务,直到现有线程数大于或等于corePoolSize。

        maximumPoolSize:线程池允许的最大线程数。

        keepAliveTime:线程存活时间。当线程池现有线程数大于核心线程数,线程池会回收空闲线程,回收的规则是,线程的空闲时间如果超过keepAliveTime,该线程会被销毁,直到线程池现有线程数小于等于核心线程数。

        timeUnit:时间单位。线程存活时间的时间单位。

        workQueue:工作队列。用于保存等待执行任务的阻塞队列。

        threadFactory:线程工厂。用于创建新线程,可以统一线程名和其他属性。

        handler:线程拒绝策略。当线程池活跃线程数等于最大线程数并且阻塞队列已满,再加入的线程会执行此策略。

下图就是threadFactory的一个例子:

java线程与线程池 java 线程池详解_线程池

线程池的拒绝策略

        线程池可选的拒绝策略有4种

                AbortPolicy:该策略会拒绝请求,并抛出RejectedExecutionException异常。

 

java线程与线程池 java 线程池详解_java线程与线程池_02

                 CallerRunsPolicy:直接运行该线程。

java线程与线程池 java 线程池详解_自定义_03

                DiscardPolicy:直接忽略,什么都不做。 

java线程与线程池 java 线程池详解_java线程与线程池_04

                DiscardOldestPolicy:将队列中最老的线程删除,将线程加入队列。 

java线程与线程池 java 线程池详解_java_05

线程池可选的阻塞队列

        线程池可选的阻塞队列有

                ArrayBlockingQueue:数组阻塞队列,有界队列,拥有FIFO的特点。

                LinkedBlockingQueue:链接阻塞队列,无界队列,默认最大长度为Integer.MAX_VALUE,拥有FIFO的特点。

                PriorityBlockingQueue:优先阻塞队列,有界队列,可以自定义排序方法。

                DelayQueue:延迟队列,无界队列,限定一段时间后获取。

                SynchronousQueue:只存储一个元素的队列,加入一个元素后put会进入阻塞状态,当消费者调用take才会被唤醒。

                LinkedTransferQueue:链接传输队列,相对LinkedBlockingQueue增加了tryTransfer和transfer方法。允许被打断。

                LinkedBlockingDeque:双向链接阻塞队列,无界队列,默认最大长度为Integer.MAX_VALUE,拥有FIFO的特点。

Java帮我们实现的几个线程池

        FixedThreadPool:特点是核心线程数与最大线程数相同,队列是使用的LinkedBlockingQueue。

java线程与线程池 java 线程池详解_线程池_06

        CachedThreadPool:特点是使用SynchronousQueue作为队列,只存储一个元素。 

java线程与线程池 java 线程池详解_java线程与线程池_07

        SingleThreadExecutor:特点是只有一个线程的线程池,创建线程池时使用了FinalizableDelegatedExecutorService,这个类多了一个finalize方法用于关闭线程池。 

java线程与线程池 java 线程池详解_阻塞队列_08

        ScheduledThreadPool:自定义核心线程数的定时器线程池。 

java线程与线程池 java 线程池详解_自定义_09

        WorkStealingPool:工作窃取线程,默认线程数是CPU的核心数,工作方式是在CPU闲置时让CPU执行任务。

java线程与线程池 java 线程池详解_java线程与线程池_10

        SingleThreadScheduledExecutor:只有一个线程的定时器线程池。

java线程与线程池 java 线程池详解_线程池_11

线程池为什么要使用阻塞队列?

阻塞队列可以使线程进入阻塞状态释放CPU资源,避免大量活跃线程排队造成资源浪费。阻塞队列可以自动阻塞和唤醒,不需要人为处理。

线程池为什么需要先加入队列再扩充活跃线程数?

首先从源码入手,源码在扩充活跃线程的时候,会加个锁,来保证线程安全。频繁的创建线程和销毁线程会降低线程池的效率,所以选择先加入阻塞队列再扩充线程。