在 Java 中,线程池是用来管理线程的一种机制,它能帮助你控制并发执行的任务,并复用线程以避免频繁地创建和销毁线程。Java 提供了多种线程池实现,可以根据不同的需求选择合适的线程池。
1. FixedThreadPool(固定大小线程池)
FixedThreadPool 是一个固定大小的线程池,线程池中的线程数是固定的。如果有多个任务提交,线程池会重用现有的线程来执行任务,直到任务数量超过线程池中的线程数。
特点:
- 固定大小的线程池。
- 如果线程池中有空闲线程,就会复用这些线程。
- 当线程数达到最大值时,其他任务会被放入队列中等待执行。
示例:
java
import java.util.concurrent.*;
public class FixedThreadPoolExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(4); // 创建一个固定大小的线程池
for (int i = 0; i < 10; i++) {
final int taskId = i;
executorService.submit(() -> {
System.out.println("执行任务:" + taskId);
try {
Thread.sleep(2000); // 模拟任务耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executorService.shutdown(); // 关闭线程池
}
}2. CachedThreadPool(可缓存线程池)
CachedThreadPool 是一个可根据需求创建新线程的线程池。如果有空闲线程,则会复用线程;如果没有空闲线程且当前没有线程处理任务,则会创建一个新线程。
特点:
- 动态创建线程,数量不固定。
- 对于长期闲置的线程,线程池会在一定时间后自动回收。
- 适合处理大量短期任务的场景。
示例:
java
import java.util.concurrent.*;
public class CachedThreadPoolExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool(); // 创建一个可缓存的线程池
for (int i = 0; i < 10; i++) {
final int taskId = i;
executorService.submit(() -> {
System.out.println("执行任务:" + taskId);
try {
Thread.sleep(2000); // 模拟任务耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executorService.shutdown(); // 关闭线程池
}
}3. SingleThreadExecutor(单线程线程池)
SingleThreadExecutor 是一个单线程的线程池,它只有一个工作线程来执行任务。如果有多个任务提交,任务会按照提交的顺序排队执行,任务之间是顺序执行的。
特点:
- 只使用一个线程执行任务,适合串行化执行的场景。
- 任务按照提交的顺序执行,保证任务执行顺序。
- 如果当前线程发生异常或被中断,线程池会创建一个新的线程继续执行任务。
示例:
java
import java.util.concurrent.*;
public class SingleThreadExecutorExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor(); // 创建一个单线程线程池
for (int i = 0; i < 10; i++) {
final int taskId = i;
executorService.submit(() -> {
System.out.println("执行任务:" + taskId);
try {
Thread.sleep(2000); // 模拟任务耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executorService.shutdown(); // 关闭线程池
}
}4. ScheduledThreadPoolExecutor(定时任务线程池)
ScheduledThreadPoolExecutor 用于执行定时任务。它可以周期性地执行任务,也可以在延迟一段时间后执行任务。
特点:
- 支持延迟任务和定期任务。
- 适用于需要定时执行任务的场景(例如,周期性的日志记录、定时清理任务等)。
示例:
java
import java.util.concurrent.*;
public class ScheduledThreadPoolExecutorExample {
public static void main(String[] args) {
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2); // 创建一个定时任务线程池
// 延迟 3 秒后执行任务
executorService.schedule(() -> {
System.out.println("延迟 3 秒执行的任务");
}, 3, TimeUnit.SECONDS);
// 每 2 秒执行一次任务
executorService.scheduleAtFixedRate(() -> {
System.out.println("定时执行的任务");
}, 0, 2, TimeUnit.SECONDS);
// 每 2 秒执行一次任务,执行完成后再等待 2 秒
executorService.scheduleWithFixedDelay(() -> {
System.out.println("定时执行并延迟的任务");
}, 0, 2, TimeUnit.SECONDS);
}
}5. WorkStealingPool(工作窃取线程池)
WorkStealingPool 是一个新的线程池实现,在 Java 8 中引入。它适用于具有多任务并行执行的场景,通过“工作窃取”机制将任务分配给空闲线程,从而提高并行度。
特点:
- 采用“工作窃取”算法,空闲的线程会窃取有任务的线程的任务。
- 适用于处理 CPU 密集型任务或者具有大量短任务的场景。
示例:
java
import java.util.concurrent.*;
public class WorkStealingPoolExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newWorkStealingPool(); // 创建一个工作窃取线程池
for (int i = 0; i < 10; i++) {
final int taskId = i;
executorService.submit(() -> {
System.out.println("执行任务:" + taskId);
try {
Thread.sleep(2000); // 模拟任务耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executorService.shutdown(); // 关闭线程池
}
}6. Custom ThreadPool (自定义线程池)
除了使用 Executors 工厂方法创建线程池外,你也可以通过 ThreadPoolExecutor 类来自定义线程池的行为。你可以指定线程池的核心线程数、最大线程数、空闲线程存活时间等参数。
示例:
java
import java.util.concurrent.*;
public class CustomThreadPoolExample {
public static void main(String[] args) {
ThreadPoolExecutor executorService = new ThreadPoolExecutor(
2, // 核心线程数
4, // 最大线程数
60, // 空闲线程存活时间
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10)); // 阻塞队列,最大容量为 10
for (int i = 0; i < 20; i++) {
final int taskId = i;
executorService.submit(() -> {
System.out.println("执行任务:" + taskId);
try {
Thread.sleep(2000); // 模拟任务耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executorService.shutdown(); // 关闭线程池
}
}总结:
- FixedThreadPool:固定大小的线程池,适合处理任务量已知且相对稳定的场景。
- CachedThreadPool:动态调整线程池大小,适合处理大量短任务。
- SingleThreadExecutor:单线程执行任务,适合串行化任务。
- ScheduledThreadPoolExecutor:定时任务线程池,适合周期性或延迟执行的任务。
- WorkStealingPool:适合 CPU 密集型任务,采用工作窃取算法提高效率。
- Custom ThreadPool (ThreadPoolExecutor):自定义线程池,可以根据需求定制线程池的行为和参数。