前言
在java中如果涉及到多任务处理,一般都会考虑使用多线程,创建多线程的方式一般有三种,即,继承Thread类、实现Runable接口、实现Callable接口,这三种方式都可以实现多线程,但是如果在程序中频繁的使用new xxThread()来创建线程,那么系统在创建和销毁线程时,相对会有性能的损耗,而且如果在不确定线程数的情况下使用new xxThread的方式来创建线程,会导致线程数不可控,可能会导致系统卡死或者崩溃,所以一般使用多线程时都会采用线程池的方式来创建或管理线程。
使用线程池的优点
1、降低了线程创建和销毁的成本,提高线程的复用性
2、线程数的可控性,可根据实际情况可伸缩的创建线程。
线程池的基本使用
public void testThreadPool() {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 3, 10L, TimeUnit.SECONDS, new ArrayBlockingQueue(1));
threadPoolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
for (int i=0; i<5; i++) {
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
// 处理业务
System.out.println(Thread.currentThread().getName() + "--运行");
}
});
}
threadPoolExecutor.shutdown();
}
线程池的原理
通过问答的形式来解答一下这些问题:
1、创建线程池构造函数的五个参数是什么:
①、核心线程数
②、最大线程数
③、空闲线程存活时间
④、线程存活时间单位
⑤、任务队列
2、线程是什么时候创建的? 首次提交线程时,线程池会创建一个线程,当第二个线程提交时,线程继续创建一个新的线程,如果当前已经创建的线程大于了核心线程数,则将新提交的线程放到任务队列中,当任务队列塞满时,如果此时创建的线程数少于最大线程数,则继续创建线程直到当前创建的线程数等于最大线程数时,表示当前线程池已经是满载状态了,需要指定任务拒绝策略。
3、空闲的线程什么时候被回收? 根据源码来看,这个方法就是移除线程的。
倒着往下看
正常情况下都是在循环自旋等待任务到来,但是如果getTask获取到为null则会退出循环,因此,getTask为null就是回收线程的时机。
继续放下看,什么情况下getTask会为null
从源码可以发现getTask返回null的情况有两种
一种是当前线程池的运行状态为SHUTDOWN并且状态为STOP或者任务队列为空。这里要说一下shutdown, 程序调用ShutDown之后,线程池并未停止运行,此时将停止添加任务,但是已经在任务队列里面的任务还是会被处理掉。当调用shutDownNow之后,任务队列将不再继续添加,已经在队列中的也不再继续处理。
另一种情况?另一种情况其实就是说当前的线程总数已经大于核心线程数,并且空闲时间已经到期。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第25天,点击查看活动详情