Java面试题

题目

请讲一下线程池的创建方法,并介绍里面几个参数的作用,并讲讲你对里面的队列的了解。

答案

创建方法

创建线程池有四种方法:

方法 描述
Executors.newFiexedThreadPool(int Threads) 创建固定数目线程的线程池。
Executors.newCachedThreadPool() 创建一个可缓存的线程池,调用 exxecute 将重以前构造的线程。如果没有线程则创建一个新的线程并且添加到池中。
Excutors.newSingleThreadExecutor() 创建一个单线程。
Excutors.newScheduledThreadPool(int corePoolSize) 创建一个支持定时及周期性的任务执行的线程池。

说明

用 Executors 方式创建线程的时候操作不当会有 OOM 的问题,主要是其创建线程池的时候用的是 LinkedBlockingQueue,是一个无界队列。一般建议用以下方式创建线程池:

public ThreadPoolExecutor(int corePoolSize, // 1 int maximumPoolSize, // 2 long keepAliveTime, // 3 TimeUnit unit, // 4 BlockingQueue<Runnable> workQueue, // 5 ThreadFactory threadFactory, // 6 RejectedExecutionHandler handler ) { //7 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 int 核心线程池大小
maximumPoolSize int 最大线程池大小
keepAliveTime long 线程最大空闲时间
unit TimeUnit 时间单位
workQueue BlockingQueue 线程等待队列
threadFactory ThreadFactory 线程创建工厂
handler RejectedExecutionHandler 拒绝策略

线程池创建过程中先将创建的线程放在核心线程池里面,如果核心线程池放满了,会将线程放在线程等待队列里面,如果线程等待队列也放满了,会将线程往线程池里面放,直到数量达到最大线程池大小。这个时候如果还有新的线程过来,会执行相应的拒绝策略。

BlockingQueue 包含下面几种:

队列名称 意义
ArrayBlockingQueue 基于数组结构的有界阻塞队列,此队列按 FIFO 原则对元素进行处理
LinkedBlockingQueue 一个基于链表结构的无界有序阻塞队列,按照 FIFO 排序元素
SynchronousQueue 不存储元素的阻塞队列,每一个插入必须等到前一个元素被移除
PriorityBlockingQueue 有优先级的无限阻塞队列

RejectedExecutionHandler 包含以下几种:

拒绝策略名称 含义
AbortPolicy 如果线程池队列满了,并且最大线程数也满了,就将这个任务丢弃,并且抛出异常
DiscardPolicy 如果队列满了,并且最大线程数也满了,就直接将任务丢弃,不会有任何异常
DiscardOldestPolicy 如果队列满了,而且最大线程数也达到了,会将老的线程丢弃,接收新的线程
CallerRunsPolicy 如果添加失败,当前的主任务来处理该线程操作。
自定义 自己定义一个拒绝策略,实现 RejectedExecutionHandler 接口