Java线程池底层源码分享和相关面试题(持续更新)

时间:2024-07-08 10:37:02

线程池各个参数讲解

public ThreadPoolExecutor(int corePoolSize, //线程池核心工作线程数量,比如newFixedThreadPool中可以自定义的线程数量就是这个参数
int maximumPoolSize, //线程池所有工作线程的数量,比如newFixedThreadPool中的最大工作线程就是核心线程数,newCachedThreadPool中的最大工作线程数是Integer.MAX_VALUE
long keepAliveTime, //非核心线程存活的时间,当核心线程不够用的时候,创建出来的辅助工作线程在完成任务空闲多久后会被回收
TimeUnit unit, //上面一个参数的单位,分。秒等
BlockingQueue<Runnable> workQueue,//底层使用的阻塞队列数据结构,比如newFixedThreadPool底层使用LinkedBlockingQueue。工作队列,保存已提交但是未执行的任务
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.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}

常用线程池

1.newSingleThreadExecutor 单个线程的线程池,即线程池中每次只有一个线程工作,单线程串行执行任务

2.newFixedThreadExecutor(n) 固定数量的线程池,没提交一个任务就是一个线程,直到达到线程池的最大数量,然后后面进入等待队列直到前面的任务完成才继续执行

3.newCacheThreadExecutor(推荐使用) 可缓存线程池,当线程池大小超过了处理任务所需的线程,那么就会回收部分空闲(一般是60秒无执行)的线程,当有任务来时,又智能的添加新线程来执行。

4.newScheduleThreadExecutor 大小无限制的线程池,支持定时和周期性的执行线程

线程池底层执行原理

Java线程池底层源码分享和相关面试题(持续更新)

日常使用中使用哪种线程池

上面四种都不使用,我们需要通过ThreadPoolExcutor自定义线程池,阿里巴巴java开发手册明确指出,不允许使用Excutors工具类进行线程池的创建,因为某些开发人员不了解底层运行规则,避免资源耗尽的危险

1:FixedThreadPool 和 SingleThreadPool: 允许的请求队列(底层实现是LinkedBlockingQueue)长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM

2:CachedThreadPool 和 ScheduledThreadPool 允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM

线程池4种拒绝策略

new ThreadPoolExecutor.AbortPolicy(); //遇到线程池达到最大线程数,且队列已经满了,直接抛异常 ----默认

new ThreadPoolExecutor.DiscardOldestPolicy() //遇到线程池达到最大线程数且队列已经满了,则丢弃队列中最前面的任务,

new ThreadPoolExecutor.DiscardPolicy() //遇到线程池达到最大线程数且队列已经满了,丢弃当前任务,不给它加入队列中

new ThreadPoolExecutor.CallerRunsPolicy();//会将任务返回给提交者进行执行,比如让main线程直接执行run方法

线程池优点

1.避免大量线程的创建销毁带来的性能开销

2.避免大量线程之间因为相互抢占系统资源导致的阻塞状态

3.能够对线程进行简单的管理并提供定时执行,间隔执行等功能

在IO密集型和CPU密集型下线程池最大线程数选择

在CPU密集型下,选用cpu核心数+1作为最大线程池工作线程数量,减少cpu切换任务带来的开销

在IO密集型下,尽可能多的加大工作线程数量,一般为cpu核心数*2

线程池提交任务时excute和submit有什么区别

1.两者接收参数不一致,excute接收Runnable接口,submit接收Callable接口

2.submit有返回值,execute没有返回值

3.submit支持返回Future

线程池状态

private static final int RUNNING    = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;

RUNNING:线程池的初始状态,可以添加待执行的任务

SHUTDOWN:线程池处于待关闭状态,不接受新任务,但会处理完已接收的任务

STOP:线程池立即关闭,不接收新的任务,放弃缓存队列中的任务并且中断正在处理的任务

TIDYING:线程池自主整理状态,调用 terminated() 方法进行线程池整理

TERMINATED:线程池终止状态