Java中的线程池概述
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池管理着多个线程,将任务分配给空闲线程执行,执行完任务的线程不会销毁,而是继续等待新的任务,从而实现线程的复用。
线程池的作用
- 降低资源消耗:通过复用已创建的线程,减少了线程创建和销毁所带来的开销,降低了系统资源的消耗。
- 提高响应速度:当有新任务提交时,由于线程已经存在,无需等待线程创建,可立即执行任务,提高了响应速度。
- 方便线程管理:线程池可以对线程进行统一的分配、调优和监控,例如可以设置线程的最大数量、控制线程的执行顺序等。
创建和使用线程池
1. 使用 Executors
工厂类创建线程池
Executors
是 Java 提供的一个线程池工厂类,它提供了一些静态方法来创建不同类型的线程池。以下是一个简单的示例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
// 创建一个固定大小的线程池,包含 3 个线程
ExecutorService executorService = Executors.newFixedThreadPool(3);
// 提交任务到线程池
for (int i = 0; i < 5; i++) {
final int taskId = i;
executorService.submit(() -> {
System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Task " + taskId + " is completed.");
});
}
// 关闭线程池
executorService.shutdown();
}
}
上述代码中,首先使用 Executors.newFixedThreadPool(3)
创建了一个固定大小为 3 的线程池,然后通过 executorService.submit()
方法向线程池提交了 5 个任务,最后调用 executorService.shutdown()
方法关闭线程池。
2. 使用 ThreadPoolExecutor
类手动创建线程池
ThreadPoolExecutor
是线程池的核心实现类,可以通过构造函数手动配置线程池的各种参数。
import java.util.concurrent.*;
public class ManualThreadPoolExample {
public static void main(String[] args) {
// 手动创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // 核心线程数
5, // 最大线程数
60, // 线程空闲时间
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10) // 任务队列
);
// 提交任务到线程池
for (int i = 0; i < 5; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Task " + taskId + " is completed.");
});
}
// 关闭线程池
executor.shutdown();
}
}
常见的线程池类型
1. 固定大小线程池(FixedThreadPool
)
使用 Executors.newFixedThreadPool(int nThreads)
方法创建,线程池中的线程数量固定,当有新任务提交时,如果有空闲线程则立即执行,否则将任务放入任务队列等待。
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
2. 单线程线程池(SingleThreadExecutor
)
使用 Executors.newSingleThreadExecutor()
方法创建,线程池只有一个线程,所有任务按照提交顺序依次执行。
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
3. 缓存线程池(CachedThreadPool
)
使用 Executors.newCachedThreadPool()
方法创建,线程池中的线程数量可以动态调整,当有新任务提交时,如果有空闲线程则立即执行,否则创建新线程执行任务。如果线程空闲时间超过 60 秒,则会被回收。
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
4. 定时线程池(ScheduledThreadPool
)
使用 Executors.newScheduledThreadPool(int corePoolSize)
方法创建,线程池可以执行定时任务和周期性任务。
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
// 延迟 2 秒后执行任务
scheduledThreadPool.schedule(() -> System.out.println("Task is executed."), 2, TimeUnit.SECONDS);
需要注意的是,从 Java 7 开始,《阿里巴巴 Java 开发手册》建议尽量不使用 Executors
工厂类来创建线程池,而是通过 ThreadPoolExecutor
手动创建,这样可以更好地控制线程池的参数,避免出现资源耗尽等问题。