目录
前言
在我们之前学习多线程的时候,使用线程往往使用的是new Thread()->{}.start()创建一个线程并启动,这种方法虽然简单,但是在实际场景并不会使用这种方法,因为一旦任务很多,频繁创建和销毁线程,会带来很大的性能损耗,甚至可能把系统拖垮。所以,Java 提供了一个更合理的线程管理方案:线程池(Thread Pool)。
一、什么是线程池?
线程池,顾名思义,就是事先创建好一批线程,统一放到一个池子里进行管理和复用。
当有任务要执行时,不着急创建一个新的线程,而是首先来到线程池看一下有没有空闲的线程可以复用;
当任务执行完毕后,线程不会销毁而是返回到线程池,供下一次调用。
核心思想:
- 预先创建一定数量的线程
- 把待执行的任务放入任务队列
- 由线程池中的线程不断从队列中取任务执行
- 线程执行完成后不销毁,继续复用
- 通过统一策略控制线程数量和任务处理方式
二、Java中的线程池
Executors是一个工具类,用来快速创建线程池。
Executors.newFixedThreadPool(5); //创建一个有上限的线程池
Executors.newCachedThreadPool(); //创建一个没有上限的线程池
示例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 1; i <= 5; i++) {
int taskId = i;
executorService.execute(() -> {
System.out.println("任务 " + taskId + " 由线程 "
+ Thread.currentThread().getName() + " 执行");
});
}
executorService.shutdown();
}
}
运行效果:

线程池中最多有 3 个线程,同时去处理 5 个任务。线程会被复用,而不是每个任务都新建一个线程。
1.execute()和submit()的区别
在线程池中,提交任务常见有两个方法:
execute()submit()
①. execute()
executorService.execute(() -> {
System.out.println("执行任务");
});
特点:
- 只能提交
Runnable - 没有返回值
- 更适合“只关心执行,不关心结果”的任务
②. submit()
Future<Integer> future = executorService.submit(() -> {
return 100;
});
特点:
- 可以提交
Runnable和Callable - 有返回值
- 返回
Future对象,可以获取执行结果
2.自定义线程池
线程池常用的构造方法如下:
public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler
)
①corePoolSize(核心线程数):线程池中长期保留的线程数量。当任务到来时,线程池会优先创建线程,直到线程数达到
corePoolSize。②maximumPoolSize(最大线程数):线程池允许创建的最大线程数量。如果核心线程都在忙,并且队列也已经满了,线程池就会创建非核心线程,直到总数达到maximumPoolSize。
③keepAliveTime(非核心线程空闲存活时间):当线程池中的线程数大于核心线程数时,多出来的那些非核心线程,如果空闲时间超过
keepAliveTime,就会被回收。④unit(时间单位):
keepAliveTime的时间单位。⑤workQueue(任务队列):当核心线程都在工作时,新来的任务会被放到任务队列中等待执行。
⑥threadFactory(线程工厂):用于创建线程。
⑦handler(拒绝策略):当线程池无法继续接收新任务时,会执行拒绝策略。
①常见拒绝策略
1. AbortPolicy
默认策略。
直接抛出异常:
RejectedExecutionException
适合对任务丢失非常敏感的场景。
2. CallerRunsPolicy
由提交任务的线程自己执行该任务。
这会让提交任务的线程“背压”,减缓任务提交速度。
3. DiscardPolicy
直接丢弃任务,不抛异常。
适合允许部分任务丢失的场景,但风险较大。
4. DiscardOldestPolicy
丢弃队列中最早的任务,然后尝试提交当前任务。
适合对“最新任务更重要”的场景。
&spm=1001.2101.3001.5002&articleId=160471628&d=1&t=3&u=905ebb30ffe34b3380366b45eb19b2d4)
1840

被折叠的 条评论
为什么被折叠?



