你对 Java 线程池理解吗?你有用过线程池吗?那先说下线程池外围参数吧。。。对不起,我回去再看看吧。
为了一丝体面,咱们明天来整顿几个面试中常考线程池面试问题吧!
为什么要用线程池?
- 线程复用。线程的重复使用是线程池设计的重点,如果须要开启 1000 个线程执行程序,零碎会创立 1000 个线程,如果用线程池来执行 1000 个工作,并不需要开启 1000 个线程,只须要设置 corePoolSize 外围线程大小数量,最大线程数量,队列大小即可反复利用线程置换工作,而且 1000 个线程切换效率并不低,也就是说线程越多效率不肯定高。所以在多线程环境理论开发中咱们举荐用多线程。
- 更好的治理线程。ThreadPoolExecutor 能够控制线程数量,依据理论利用场景设置队列数量和饱和策略。
你说下线程池外围参数?
- corePoolSize:外围线程大小。线程池始终运行,外围线程就不会进行。
- maximumPoolSize:线程池最大线程数量。非核心线程数量 =maximumPoolSize-corePoolSize
- keepAliveTime:非核心线程的心跳工夫。如果非核心线程在 keepAliveTime 内没有运行工作,非核心线程会沦亡。
- workQueue:阻塞队列。ArrayBlockingQueue,LinkedBlockingQueue 等,用来寄存线程工作。
- defaultHandler:饱和策略。
- ThreadFactory:线程工厂。新建线程工厂。
execute 工作增加流程?
- 线程池执行 execute/submit 办法向线程池增加工作,当工作小于外围线程数 corePoolSize,线程池中能够创立新的线程。
- 当工作大于外围线程数 corePoolSize,就向阻塞队列增加工作。
- 如果阻塞队列已满,须要通过比拟参数 maximumPoolSize,在线程池创立新的线程,当线程数量大于 maximumPoolSize,阐明以后设置线程池中线程曾经解决不了了,就会执行饱和策略。
饱和策略晓得吗?
上图咱们说过,当线程数量大于 maximumPoolSize,就会执行饱和策略。ThreadPoolExecutor 类中一共有 4 种饱和策略。通过实现 RejectedExecutionHandler 接口。
- AbortPolicy:线程工作抛弃报错。默认饱和策略。
- DiscardPolicy:线程工作间接抛弃不报错。
- DiscardOldestPolicy:将 workQueue队首工作抛弃,将最新线程工作重新加入队列执行。
- CallerRunsPolicy:线程池之外的线程间接调用 run 办法执行。
上面咱们在代码中看下饱和策略应用形式。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author:jiaolian
* @date:Created in 2021-02-20 16:28
* @description:线程池抛弃策略
* @modified By:* 公众号: 叫练 */public class AbortTest {
// 线程数量
private static final int THREAD_COUNT = 50;
private static final CountDownLatch COUNT_DOWN_LATCH = new CountDownLatch(THREAD_COUNT);
private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger(1);
// 线程池抛弃策略
public static void main(String[] args) throws InterruptedException {
// 新建一个线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
3,5,1, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(20),new ThreadPoolExecutor.AbortPolicy());
//DiscardPolicy 抛弃
//AbortPolicy 抛弃报错 //DiscardOldestPolicy 将队列对首的工作抛弃, 执行以后线程工作 //CallerRunsPolicy 间接调用 run 办法
// 提交线程 for (int i=0; i<THREAD_COUNT; i++) {threadPoolExecutor.execute(()->{
try {Thread.sleep(2000);
} catch (InterruptedException e) {e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"execute!"+ATOMIC_INTEGER.getAndIncrement());
COUNT_DOWN_LATCH.countDown();});
}
COUNT_DOWN_LATCH.await();
// 敞开线程
threadPoolExecutor.shutdown();}
}
如上代码:外围线程数量是 3,最大线程数量是 5,阻塞队列是 20,共提交 50 个线程,这里饱和策略用的是 AbortPolicy,剖析执行线程池过程,线程池中首先开启 3 个外围线程 Worker,发现 3 个线程解决不了 50 个线程工作,于是线程池就向阻塞队列增加工作,发现还是阻塞队列也包容不下 50 个工作,于是又减少至 2 个线程同时运行线程工作,一共是 5 个线程同时运行工作,此时线程池中共有 25 个工作会被执行,还有 25 个工作会被抛弃,因为咱们用的是 AbortPolicy 饱和策略,会报错,截局部图如下划红线所示。一共执行了 25 个工作。其余几种策略大家能够参照执行。
你平时线程池怎么用的?
- Excutors.newSingleThreadExecutor:1 个 corePoolSize,LinkedBlockingQueue 队列无限大,当创立无数个线程,队列有限长,可能呈现 OOM 内存溢出。繁多线程。
- Executors.newCachedThreadPool:0 个 corePoolSize,Interger.MAX_VALUE个 最大线程数,当创立无数个线程,可能呈现 OOM 内存溢出。实用小而多线程。
- Executors.newFixedThreadPool:n 个 corePoolSize,n 个 最大线程个数,LinkedBlockingQueue 阻塞队列,当创立无数个线程,队列有限长,可能呈现 OOM 内存溢出。实用固定线程。
- Executors.newScheduledThreadPool:n 个 corePoolSize,Interger.MAX_VALUE 个最大线程数,当创立无数个线程,可能呈现 OOM 内存溢出。
源码中线程池是怎么复用线程的?
源码中 ThreadPoolExecutor 中有个内置对象 Worker,每个 worker 都是一个线程,worker 线程数量和参数无关,每个 worker 会 while 死循环从阻塞队列中取数据,通过置换 worker 中 Runnable 对象,运行其 run 办法起到线程置换的成果,这样做的益处是防止多线程频繁线程切换,进步程序运行性能。
总结
明天咱们介绍了线程池中面试中几个重要的面试点,整理出来心愿能对你有帮忙,写的比不全,同时还有许多须要修改的中央,心愿亲们加以斧正和点评,喜爱的请点赞加关注哦。点关注,不迷路,我是 叫练【公众号】,微信号【jiaolian123abc】边叫边练。