# 线程池
# 简要回答
- 采用多线程编程时,如果线程过多会造成系统资源的大量占用,降低系统效率。如果有些线程存活时间短但是不得不创建很多时也会造成资源浪费,线程池可以决定由哪个空闲且存活的线程来执行,当线程池中线程不够时会适当创建一部分线程,线程冗余时会销毁一部分线程。可以提高线程利用率,降低系统资源损耗。
# 详细回答
- 资源管理: 在多线程应用中线程池提供了对线程的统一管理(如任务队列、线程生命周期监控、拒绝策略等),方便开发者跟踪任务执行状态、调整资源分配。
- 提高性能:线程的创建和销毁开销相对较大。线程池可以复用线程,避免频繁地创建和销毁线程从而提高系统性能。
- 任务排队:线程池可以用于排队任务,确保任务按照一定的顺序执行,避免线程竞争和冲突
- 避免线程过多:如果不使用线程池,程序员可能会手动创建大量线程来处理任务,每个线程都需要占用内存和CPU资源,如果不加限制地创建线程,会导致系统资源耗尽,可能引发系统崩溃。线程池通过限制线程数量来避免这种情况。
# 使用场景
- 线程池适用于需要频繁创建和销毁线程场景,如:处理大量数据,执行大量计算任务,处理大量IO任务。
- 线程池适用于需要控制并发规模的场景,如:Web服务器、数据库连接池、消息队列等。
- 线程池适用于需要提升任务调度与管理场景,线程池的getActiveCount()监控可以实时活跃线程数。
# 代码示例
- 固定线程池使用示例
import java.util.concurrent.Executorservice;
import java.util.concurrent.Executors;
public class ResourceManagementExample{
public static void main(string[] args){
//创建一个固定大小的线程池,包含3个线程
ExecutorService executor=Executors.newFixedThreadPool(3);
// 提交任务给线程池
for(int i=0;i<5;i++){
final int taskId = i;
executor.submit(()->{
System.out.printIn("Task "+ taskId +" is running on thread "+ Thread.currentThread().getName());});
}
// 关闭线程池
executor.shutdown();
}
}
// 运行结果:
Task 1 is running on thread pool-1-thread-2
Task 0 is running on thread pool-1-thread-1
Task 2 is running on thread pool-1-thread-3
Task 3 is running on thread pool-1-thread-2
Task 4 is running on thread pool-1-thread-1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- 可缓存线程池使用示例
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ImprovedPerformanceExample{
public static void main(string[] args){
ExecutorService executor =Executors.newCachedThreadPool();
for(int i=0;i<5;i++){
final int taskedId=i;
executor.submit(()->{
System.out.println("Task "+ taskId +" is running on thread "+ Thread.currentThread().getName());
});
}
executor.shutdown();
}
}
//运行结果:
Task 4 is running on thread pool-1-thread-5
Task 1 is running on thread pool-1-thread-2
Task 2 is running on thread pool-1-thread-3
Task 3 is running on thread pool-1-thread-4
Task 0 is running on thread pool-1-thread-1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- 单线程线程池使用场景
import java.util.concurrent.Executorservice;import java.util.concurrent.Executors;
public class TaskQueueExample {
public static void main(string[]args){
//创建一个单线程线程池,任务会按顺序执行
ExecutorService executor =Executors.newSingleThreadExecutor();
//提交多个任务给线程池
for(inti=0;i<5;i++){
final int taskId = i;
executor.submit(()->{
System.out.println("Task "+ taskId + " is running on thread "+ Thread.currentThread().getName());
});
}
// 关闭线程池
executor.shutdown();
}
}
// 运行结果:
Task 0 is running on thread pool-1-thread-1
Task 1 is running on thread pool-1-thread-1
Task 2 is running on thread pool-1-thread-1
Task 3 is running on thread pool-1-thread-1
Task 4 is running on thread pool-1-thread-1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 知识图解
- 线程池工作原理

# 知识扩展
- 扩展:
- 线程池种类:
- ScheduledThreadPoolExecutor:定时执行任务,支持定时执行和周期执行。
- FixedThreadPool:固定大小线程池,线程数量固定,核心线程数和最大线程数相同,不会创建更多线程处理任务。
- CachedThreadPool:可缓存线程池,在于线程数是几乎可以无限增加(最大Integer.MAX_VALUE,2^31-1),线程闲置时会进行回收。
- SingleThreadExecutor:使用唯一的线程去执行任务,原理和FixedThreadPool一样,如果线程在执行任务时发生异常,会重新创建新线程执行后续任务,适合所有任务需要按顺序执行场景。
- SingleThreadScheduledExecutor:和ScheduledThreadPool线程池相似,属于其特例,内部只有一个线程。
- 面试官可能追问:
- Q1:线程池越多越好吗?一个线程池有大量线程会怎样?
- 资源竞争加剧,性能下降。每个线程池也会占用一定内存空间,过多的线程池同样会导致内存占用。
- 过多的线程池会增加代码维护成本,难以统一各线程池状态。
- 如果多个线程池之间存在资源依赖,可能会导致死锁,同时过多线程池可能耗尽系统的线程资源。
- 大量线程竞争CPU时间片,会增加上下文切换的频率,降低系统整体效率。
- 操作系统调度线程池中的所有线程,线程数量越多调度器负担越重,可能会导致关键任务延迟执行。
- Q2:线程池工作队列满了有哪些拒接策略?
- 如果线程池的任务队列满了,线程池会执行指定的拒绝策略来应对,常用的四种拒绝策略包括:
- CallerRunsPolicy:使用线程池调用者所在的线程去执行被拒绝的任务,除非线程池被停止或者线程池的任务队列已有空缺。
- AbortPolicy:直接抛出一个任务被线程池拒绝的异常。
- DiscardPolicy:不做任何处理,然后执行该任务。
- DiscardOldestPolicy:抛弃最老的任务,然后执行该任务。
- 自定义拒绝策略,通过实现RejectedExecutionHandler接口可以自定义任务的拒绝处理逻辑。
- 如果线程池的任务队列满了,线程池会执行指定的拒绝策略来应对,常用的四种拒绝策略包括:
评论
验证登录状态...