1. Why(为什么要使用线程池)

- 创建和销毁线程需要消耗系统资源,线程池可以复用已创建的线程

- 控制并发的数量。并发数量不加控制,可能会导致系统资源耗尽,造成服务器崩溃(主要原因)

- 对线程做统一管理

2. What(线程池的原理)

参数说明

corePoolSize 核心线程数

maximumPoolSize 最大线程数

keepAliveTime 线程存活时间

unit 时间单位,枚举类型(NANOSECONDS:微毫秒;MICROSECONDS:微秒;MILLISECONDS:毫秒;SECONDS:秒;MINUTES:分钟;HOURS:小时;DAYS:天;)

BlockingQueue<Runnable> workQueue 等待执行的任务对象

ThreadFactory threadFactory 线程工厂

RejectedExecutionHandler handler 拒绝策略

重点

  • BlockingQueue

任务对象又分为4中类型

ArrayBlockingQueue 数组阻塞队列,底层数据结构是数组。

LinkedBlockingQueue 链式阻塞队列,底层数据结构是链表。

SynchronousQueue 同步队列,内部容量为0。每个put操作必须等待一个take操作,反之亦然。

BlockingQueue 延迟队列,该队列中的元素只有当其指定的延时时间到了,才能从队列中获取到该元素。
  • ThreadFactory

创建线程的工厂,用于批量创建线程,统一在创建线程时候设置一些参数。如:是否是守护线程、线程优先级等。

  • RejectedExecutionHandler

拒绝处理策略。当线程数大于最大执行线程数就会采用拒绝处理策略,有4中拒绝处理策略:

1. ThreadPoolExecutor.CallerRunsPolicy(); // 由调用线程处理该任务

2. ThreadPoolExecutor.AbortPolicy(); //默认拒绝处理策略,丢弃任务并抛出RejectedExecutionException异常

3. ThreadPoolExecutor.DiscardPolicy(); //丢弃新来的任务,但不抛出异常

4. ThreadPoolExecutor.DiscardOldestPolicy(); //丢弃队列头部(最旧的)任务,然后重新执行程序

java线程池执行流程
java线程池执行流程

工作原理:

1. 线程池首先判断当前在运行的线程是否少于corePoolSiz(核心线程数)。如果是,则创建一个新的工作线程来执行任务;如果不是,进入2。
2. 判断BlockingQueue(工作队列)是否已经满了。如果还没满,将线程放入BlockingQueue;如果已满,进入3。
3. 判断当前运行的线程是否大于maximumPoolSize(最大线程数)。如果不是分配一个新的任务给空闲的线程执行;如果线程池满了,则交给RejectedExecutionHandler(饱和策略)来处理任务。

3. How(怎么用)

1. newCachedThreadPool

 private static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
        new SynchronousQueue<>());
  }

特点:

1. newCachedThreadPool线程池中最大线程数可达到Integer.MAX_VALUE,即2147483647,内部使用SynchronousQueue阻塞队列;
2. newCachedThreadPool线程池在没有任务执行时,当线程空闲时间超过keepAliveTime,会自动释放线程资源。

2. newFixedThreadPool

  public static ExecutorService newFixedThreadPool(int corePoolSize) {
    return new ThreadPoolExecutor(corePoolSize, corePoolSize, 0L, TimeUnit.SECONDS,
        new LinkedBlockingQueue<>());
  }

特点:

1. 线程池中的线程数达到corePoolSize后,即使工作队列中没有可执行的任务,也不会释放线程;
2. FixedThreadPool的工作队列为无界队列LinkedBlockingQueue(队列的容量为Integer.MAX_VALUE=0x7fffffff,即2^31-1=2147483647);
3. 因为无界队列,这也导致maximumPoolSize、keepAliveTime将不生效;
4. 使用了无界队列,工作队列也就不会满,RejectedExecutionHandler也就不会生效,即饱和策略失效

kanelli
1 声望1 粉丝

拥抱改变,持续学习。