Java线程池与连接池
简介
在并发编程中,线程池和连接池是两个非常重要的概念。线程池用于管理和复用线程资源,而连接池用于管理和复用数据库连接等资源。本文将介绍Java中的线程池和连接池的概念、原理和使用方法,并给出相关的代码示例。
线程池
概念
线程池是一种用于管理和复用线程资源的机制。在多线程编程中,频繁地创建和销毁线程会带来较大的开销。线程池通过预先创建一定数量的线程,并将这些线程组织成池子,以供任务使用。任务执行完毕后,线程并不销毁,而是返回到池子中等待下一次任务的到来,从而避免了频繁创建和销毁线程的开销。
原理
Java提供了java.util.concurrent.ThreadPoolExecutor
类作为线程池的实现。可以通过以下方式创建一个线程池:
ExecutorService executorService = Executors.newFixedThreadPool(10);
上述代码创建了一个固定大小为10的线程池。线程池的核心参数有以下几个:
- corePoolSize:核心线程数,即最小的可同时执行的线程数。
- maximumPoolSize:最大线程数,即线程池中最多同时执行的线程数。
- keepAliveTime:线程的空闲时间,当线程空闲时间超过该值时,多余的线程会被销毁。
- workQueue:任务队列,用于存放待执行的任务。
线程池的工作流程如下:
- 当一个任务到达时,线程池首先检查核心线程池是否已满。如果未满,则创建一个新线程执行任务。
- 如果核心线程池已满,线程池会将任务放入任务队列中。
- 当任务队列已满时,线程池会创建新线程执行任务,直到达到最大线程数。
- 如果线程池的线程数已达到最大线程数,并且任务队列已满,则线程池会根据拒绝策略来处理新的任务。常见的拒绝策略有抛出异常、阻塞调用者、丢弃任务等。
示例
下面是一个简单的示例,展示了如何使用线程池执行一些耗时的任务:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
int taskId = i;
executorService.execute(() -> {
System.out.println("Task " + taskId + " is running.");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Task " + taskId + " is completed.");
});
}
executorService.shutdown();
}
}
上述代码创建了一个固定大小为5的线程池,并提交了10个任务给线程池执行。每个任务会打印自己的ID,然后睡眠1秒钟,最后完成任务。可以看到,线程池会自动复用线程,以提高执行效率。
连接池
概念
连接池是一种用于管理和复用数据库连接等资源的机制。在访问数据库时,频繁地创建和关闭连接会带来较大的开销。连接池通过预先创建一定数量的连接,并将这些连接组织成池子,以供程序使用。程序使用连接时,从池子中获取一个连接,使用完毕后归还到池子中,从而避免了频繁创建和关闭连接的开销。
原理
Java提供了javax.sql.DataSource
接口作为连接池的抽象。常见的连接池实现有HikariCP
、Apache DBCP
等。连接池的工