ThreadPoolExecutor用于管理和复用线程,能提高多线程应用程序的性能和资源利用率。
线程池创建
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 创建一个固定大小的线程池,大小为3
ThreadPoolExecutor executor = new ThreadPoolExecutor(
3, 3, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()
);
//注: LinkedBlockingQueue无界队列,如果队列变得太长,将会导致等待时间增加,系统负载加重,影响整体性能,
// 可能会造成内存耗尽
// 可以使用ArrayBlockingQueue 加拒绝策略来创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
3, 3, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(10), new DiscardOldestPolicy()
);
// 提交任务给线程池执行
// 无返回值的直接execute就行
executor.execute(new Task("Task 1"));
// 关闭线程池
executor.shutdown();
// 有返回值的用submit,Future对象用于接收返回结果
Future<Integer> future = executor.submit(new Task());
try {
// 阻塞等待任务执行完成并获取结果
int result = future.get();
System.out.println("Task result: " + result);
} catch (Exception e) {
e.printStackTrace();
}
// 关闭线程池
executor.shutdown();
}
//若要线程有返回,实现callable接口
static class TaskWithReturn implements Callable<Integer> {
public Integer call() {
System.out.println("Executing task...");
// 执行具体的任务逻辑,并返回结果
// ...
return 42;
}
}
//若线程无返回,任务实现Runnable接口即可
static class Task implements Runnable {
private String name;
public Task(String name) {
this.name = name;
}
public void run() {
System.out.println("Executing task: " + name);
// 执行具体的任务逻辑
// ...
}
}
static class DiscardOldestPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
if (!executor.isShutdown()) {
// 丢弃最旧的任务并尝试执行当前任务
executor.getQueue().poll();
executor.execute(r);
}
}
}
}
线程池工作流程
引:[线程池工作流程][https://zhuanlan.zhihu.com/p/201427009]
注意:只有阻塞队列满了才开始创建救急线程。
核心线程数、最大线程数、阻塞队列大小的确定
- 核心线程数是线程池中始终保持活动的线程数量。对于 CPU 密集型任务,可以将核心线程数设置比处理器核心数量稍多 T+1,以充分利用系统资源。
- 对于 I/O 密集型任务,可以将核心线程数设置得更高,如2T,以处理可能的 I/O 阻塞导致的线程等待。
- 核心线程数设置得太小,可能导致线程频繁创建和销毁,影响性能;设置得太大,可能会占用过多的系统资源。根据任务类型和系统负载,选择一个合适的值。