Java线程池在Java面试经常被问到,比如:Java线程池作用,以及Java线程池的原理和使用等,下面我一一来详解@mikechen
Java线程池定义
Java线程池,全称是Java Thread Pool,是一种池化技术,主要通过池化思想管理线程的工具,用于管理和调度线程。
Java线程池作用
Java线程池的作用,主要包含如下4点:
1.提高性能
线程池可以重复利用已创建的线程,避免了频繁创建和销毁线程的开销。
2.提高可管理性
通过限制线程的数量和队列的大小,可以更好地管理系统资源。
3.提高响应能力
由于线程已经准备好,可以更快地响应任务请求,如果每次任务请求都需要创建一个新的线程,那么响应时间将会比使用线程池更长。
4.更好的任务调度
线程池可以通过任务队列来调度任务的执行顺序,避免任务之间的互相干扰和相互等待。
Java线程池创建
Java线程池创建,如要包含如下几种:
1.创建一个固定大小的线程池
如下所示:
ExecutorService executor = Executors.newFixedThreadPool(5);
这种方式会创建一个固定大小的线程池,这种线程池适合任务量比较稳定的场景。
2.创建一个只有一个线程的线程池
如下所示:
ExecutorService executor = Executors.newSingleThreadExecutor();
该线程池只有一个线程,这种线程池适合需要顺序执行任务,保证任务按照一定顺序执行的场景。
3.创建⼀个可缓存的线程池
如下所示:
ExecutorService executor = Executors.newCachedThreadPool();
创建⼀个可缓存的线程池,若线程数超过处理所需,缓存⼀段时间后会回收,这种线程池适合短时间内需要大量线程的场景。
4.创建定时周期固定的线程池
如下所示:
ScheduledExecutorService executor = Executors.newScheduledThreadPool(5); executor.schedule(new MyTask(1), 5, TimeUnit.SECONDS); executor.scheduleAtFixedRate(new MyTask(2), 1, 5, TimeUnit.SECONDS); executor.shutdown();
这个线程池就是为了定时而发明的,它支持定时或周期性执行任务,比如:10秒钟执行一次任务。
5.创建定时或周期性任务的单个线程池
如下所示:
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); executor.schedule(new MyTask(1), 5, TimeUnit.SECONDS); executor.scheduleAtFixedRate(new MyTask(2), 1, 5, TimeUnit.SECONDS); executor.shutdown();
创建一个只有一个线程的线程池,可以用来执行定时或周期性任务。
6.创建工作窃取线程池
如下所示:
ExecutorService executor = Executors.newWorkStealingPool(); for (int i = 0; i < 10; i++) { executor.execute(new MyTask(i)); } executor.shutdown();
创建一个工作窃取线程池,当一个线程执行完自己的任务队列中的任务后,就会从其他线程的任务队列中窃取任务来执行,适合使用在很耗时的操作。
7.最原始的创建线程池的⽅式
可以通过ThreadPoolExecutor 手动创建线程池,这也是阿里等大厂推荐使用方式。
Java线程池参数
如下所示:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
以下是Java自定义线程池的7大参数说明:
Java线程池使用
下面是一个简单的Java线程池创建示例:
// 创建一个线程池,包括5个核心线程和10个最大线程,线程存活时间为1分钟,使用默认的任务队列和拒绝策略 ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>()); // 提交任务 executor.execute(new Runnable() { public void run() { // 任务执行的代码 } }); // 关闭线程池 executor.shutdown();
在创建线程池时,需要根据实际需求灵活配置线程池的大小、任务队列类型和线程的创建方式等参数,以达到最佳的性能和效果。
Java线程池原理
线程池的工作原理,如下图所示:
线程池的工作流程,主要分为如下5步:
1.检查线程池是否已满
当一个任务需要执行时,线程池会检查线程池中是否有空闲的线程可用,如果有,那么一个空闲的线程会被分配给该任务执行。
2.将任务放入队列
如果线程池中没有空闲的线程可用,那么任务会被放到任务队列中等待执行,直到有空闲的线程可用。
3.准备开始处理任务
当一个线程完成了任务的执行后,它会返回线程池,并且准备处理下一个任务。
4.如果已满执行拒绝策略
如果线程池中的线程数量已经达到了限制,而且任务队列已经满了,那么线程池会拒绝该任务并执行拒绝策略。
常见的拒绝策略有以下4种,如下图所示:
更加想的拒绝策略,请查看:Java线程池拒绝策略详解(4种常见拒绝策略)
5.释放线程池资源
当应用程序关闭时,线程池会关闭所有的工作线程,并释放相关的资源。
Java线程池应用
具体来说,在以下几种情况下建议使用Java线程池:
- 处理IO密集型任务,例如读写文件、网络传输等。
- 处理CPU密集型任务,例如加密解密、图像处理等。
- 需要处理大量任务的并发环境,例如Web服务器、消息队列等。
- 需要对任务进行优先级排序或按照一定规则进行调度的情况。
以上就是Java线程池的详解,希望对你掌握Java线程池有所帮助!
陈睿mikechen
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》