多线程常见面试题

1.Java线程池有哪些核心参数,分别有什么的作用?

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(        

                 8,        

                16,        

                60,        

                TimeUnit.SECONDS,        

                new ArrayBlockingQueue<Runnable>(1024),                         Executors.defaultThreadFactory(),        

                new ThreadPoolExecutor.CallerRunsPolicy() );

构造方法最多的是7个参数;

(1)int corePoolSize, 线程池中的核心线程数量 allowCoreThreadTimeOut;允许核心线程超时销毁; boolean prestartCoreThread(),初始化一个核心线程; int prestartAllCoreThreads(),初始化所有核心线程;

(2)int maximumPoolSize, 线程池中允许的最大线程数,当核心线程全部繁忙且任务队列存满之后,线程池会临时追加线程,直到总线程数达到maximumPoolSize这个上限;

(3)long keepAliveTime, 线程空闲超时时间,如果一个线程处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,这个空闲线程会被销毁;

(4)TimeUnit unit, keepAliveTime的时间单位 (天、小时、分、秒......);

(5)BlockingQueue<Runnable> workQueue, 任务队列,当核心线程全部繁忙时,任务存放到该任务队列中,等待被核心线程来执行;

(6)ThreadFactory threadFactory, 线程工厂,用于创建线程,一般采用默认的线程工厂即可,也可以自定义实现;

Executors.defaultThreadFactory(),

Executors.privilegedThreadFactory(),(过时)

(7)RejectedExecutionHandler handler, 拒绝策略(饱和策略),当任务太多来不及处理时,如何“拒绝”任务?

1、核心线程corePoolSize正在执行任务;

2、线程池的任务队列workQueue已满;

3、线程池中的线程数达到maximumPoolSize时;

就需要“拒绝”掉新提交过来的任务;

2.线程池有哪些拒绝策略? 

JDK提供了4种内置的拒绝策略:

AbortPolicy、

CallerRunsPolicy、

DiscardOldestPolicy、

DiscardPolicy;

1、AbortPolicy(默认):丢弃任务并抛出RejectedExecutionException异常,这是默认的拒绝策略;

2、DiscardPolicy:直接丢弃任务,不抛出异常,没有任何提示;

3、DiscardOldestPolicy:丢弃任务队列中靠最前的任务,当前提交的任务不会丢弃;

4、CallerRunsPolicy: 交由任务的调用线程(提交任务的线程)来执行当前任务;

除了上面的四种拒绝策略,还可以通过实现RejectedExecutionHandler接口,实现自定义的拒绝策略; 

3.说一说线程池的执行流程? 

 当提交一个新任务到线程池时,具体的执行流程如下:

1. 当我们提交任务,线程池会根据corePoolSize大小创建线程来执行任务;

2. 当任务的数量超过corePoolSize数量,后续的任务将会进入阻塞队列阻塞排队;

3. 当阻塞队列也满了之后,那么将会继续创建(maximumPoolSize-corePoolSize)个数量的线程来执行任务,如果任务处理完成,maximumPoolSize-corePoolSize个额外创建的线程等待 keepAliveTime之后被自动销毁;

4. 如果达到maximumPoolSize,阻塞队列还是满的状态,那么将根据不同的拒绝策略进行拒绝处理;

4.线程池核心线程数怎么设置呢? 

Ncpu = cpu的核心数 ,Ucpu = cpu的使用率(在0~1之间)

W = 线程等待时间,C = 线程计算时间

举例:

8 * 100% * (1+60/40) = 20

8 * 100% * (1+80/20) = 40 

任务分为CPU密集型和IO密集型

CPU密集型

        线程数 = CPU核心数 + 1; 这种任务主要是消耗CPU资源, 比如像加解密、压缩、计算等一系列需要大量耗费 CPU 资源的任务; +1,比 CPU 核心数多出来的一个线程是为了防止线程偶发的缺页中断,或者其它原因导致的任务暂停而带来的影响。一旦任务暂停,CPU 就会处于空闲状态,而在这种情况下多出来的一个线程就可以充分利用 CPU 的空闲时间; 

IO密集型

        线程数 = CPU核心数 * 2; 这种任务会有大部分时间在进行IO操作,比如像MySQL数据库、文件读写、网络通信等任务,这类任务不会特别消耗CPU资源,但是IO操作比较耗时,会占用比较多时间; 线程在处理IO的时间段内不会占用CPU,这时就可以将CPU交出给其它线程使用,因此在IO密集型任务的应用中,可以多配置一些线程;

基本原则:

1、线程执行时间越多,就需要越少的线程;

2、线程等待时间越多,就需要越多的线程;

以上理论参考依据,实际项目中建议在本地或者测试环境进行压测多次调整线程池大小,找到相对理想的值大小;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青山猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值