一、什么是线程池?

线程池就是首先创建一些线程,它们的集合称为线程池。使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务。
使用线程池的原因:
多线程运行时间,系统不断的启动和关闭新线程,成本非常高,会过渡消耗系统资源,以及过渡切换线程的危险,从而可能导致系统资源的崩溃。这时,线程池就是最好的选择了。

二、创建线程是的方式1—— ThreadPoolExecutor类

2.1 参数含义

java.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类。

ThreadPoolExecutor类中提供了四个构造方法:

iOS protobuf线程管理_java


下面解释下一下构造器中各个参数的含义:

  • corePoolSize核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
  • maximumPoolSize线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程;
  • keepAliveTime表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
  • unit参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:
  • workQueue线程池中的任务队列,该队列主要用来存储已经被提交但是尚未执行的任务。存储在这里的任务是由ThreadPoolExecutor的execute方法提交来的。
  • threadFactory : 为线程池提供创建新线程的功能,这个我们一般使用默认即可
  • handler拒绝策略,当线程无法执行新任务时(一般是由于线程池中的线程数量已经达到最大数或者线程池关闭导致的),默认情况下,当线程池无法处理新线程时,会抛出一个RejectedExecutionException。

2.2 创建线程池

package com.lsh.threadpool;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author :LiuShihao
 * @date :Created in 2020/12/17 3:45 下午
 * @desc : 使用ThreadPoolExecutor创建线程池
 * 在阿里巴巴Java开发手册中提到,使用Executors创建线程池可能会导致OOM(OutOfMemory ,内存溢出)
 */
public class CreateThreadPoolExecutor {
    public static void main(String[] args) {
        /**
         * corePoolSize     线程池核心线程数量  10
         * maximumPoolSize  线程池最大数量     15
         * keepAliveTime    空闲线程存活时间   60秒
         * unit => 时间单位
         * workQueue => 线程池所使用的缓冲队列
         * threadFactory => 线程池创建线程使用的工厂
         * handler => 线程池对拒绝任务的处理策略
         *
         */
        ExecutorService executor = new ThreadPoolExecutor(10, 15,60L, TimeUnit.SECONDS, new ArrayBlockingQueue(10));
        for (int i = 0; i < 20; i++) {
            int num = i;
            executor.execute(() ->{
                System.out.println(Thread.currentThread().getName()+"    "+num);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        executor.shutdown();

    }
}

三、创建线程是的方式一 Executors执行器

在阿里巴巴Java开发手册中提到,使用Executors创建线程池可能会导致OOM(OutOfMemory ,内存溢出)

iOS protobuf线程管理_线程池_02

iOS protobuf线程管理_java_03


四种常用的线程池:

3.1 固定线程池

FixedThreadPool 固定线程池

Fixed中文解释为固定。结合在一起解释固定的线程池,说的更全面点就是,有固定数量线程的线程池。其corePoolSize=maximumPoolSize,且keepAliveTime为0,适合线程稳定的场所。

iOS protobuf线程管理_新星计划_04

3.2 可缓存线程池

CachedThreadPool 缓存线程池

Cached中文解释为储存。结合在一起解释储存的线程池,说的更通俗易懂,既然要储存,其容量肯定是很大,所以他的corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE(2^32-1一个很大的数字)

iOS protobuf线程管理_新星计划_05

3.3 可定时线程池

ScheduledThreadPool 定时任务线程池

Scheduled中文解释为计划。结合在一起解释计划的线程池,顾名思义既然涉及到计划,必然会涉及到时间。所以ScheduledThreadPool是一个具有定时定期执行任务功能的线程池。

iOS protobuf线程管理_多线程_06

3.4 单例线程池

SingleThreadPool 单例线程池

Single中文解释为单一。结合在一起解释单一的线程池,说的更全面点就是,有固定数量线程的线程池,且数量为一,从数学的角度来看SingleThreadPool应该属于FixedThreadPool的子集。其corePoolSize=maximumPoolSize=1,且keepAliveTime为0,适合线程同步操作的场所。

iOS protobuf线程管理_线程池_07