为了避免系统频繁地创建和销毁线程,我们可以让创建的线程复用。如果大家进行过数据库开发,那么对数据库连接池应该不会陌生。为了避免每次数据库查询都重新建立和销毁数据库连接,我们可以使用数据库连接池维护一些数据库连接,让它们长期保持在一个激活状态。当系统需要使用数据库时,并不是创建一个新的连接,而是从连接池中获得一个可用的连接即可。反之,当需要关闭连接时,并不真的把连接关闭,而是将这个连接“还”给连接池即可。这种方式可以节约不少创建和销毁对象的时间。
线程池也是类似的概念。在线程池中,总有那么几个活跃线程。当你需要使用线程时,可以从池子中随便拿一个空闲线程,当完成工作时,并不急着关闭线程,而是将这个线程退回到线程池中,方便其他人使用。
简而言之,在使用线程池后,创建线程变成了从线程池获得空闲线程,关闭线程变成了向线程池归还线程,如图所示。
JDK对线程池的支持Executor框架提供了各种类型的线程池,主要有以下工厂方法:
public static ExecutorService newFixedThreadPool(int nThreads) public static ExecutorService newSingleThreadExecutor() public static ExecutorService newCachedThreadPool() public static ExecutorService newSingleThreadScheduledExecutor() public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
以上工厂方法分别返回具有不同工作特性的线程池。这些线程池工厂方法的具体说明 如下。
- newFixedThreadPool
该方法返回一个固定线程数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执
行。若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理任务队列中的任务
public class ThreadPoolDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
executorService.execute(() -> {
System.out.println("ThreadPoolDemo.main" + Thread.currentThread().getName());
Sleep.sleep(1000);
});
}
}
}
结果
ThreadPoolDemo.mainpool-1-thread-1 ThreadPoolDemo.mainpool-1-thread-2 ThreadPoolDemo.mainpool-1-thread-3 ThreadPoolDemo.mainpool-1-thread-4 ThreadPoolDemo.mainpool-1-thread-5 ThreadPoolDemo.mainpool-1-thread-2 ThreadPoolDemo.mainpool-1-thread-3 ThreadPoolDemo.mainpool-1-thread-5 ThreadPoolDemo.mainpool-1-thread-4 ThreadPoolDemo.mainpool-1-thread-1
- newSingleThreadExecutor
该方法返回一个只有一个线程的线程池。若多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
executorService.execute(() -> {
System.out.println("ThreadPoolDemo.main" + Thread.currentThread().getName());
Sleep.sleep(1000);
});
}
}
结果:
ThreadPoolDemo.mainpool-1-thread-1 ThreadPoolDemo.mainpool-1-thread-1 ThreadPoolDemo.mainpool-1-thread-1 ThreadPoolDemo.mainpool-1-thread-1 ThreadPoolDemo.mainpool-1-thread-1 ThreadPoolDemo.mainpool-1-thread-1 ThreadPoolDemo.mainpool-1-thread-1 ThreadPoolDemo.mainpool-1-thread-1 ThreadPoolDemo.mainpool-1-thread-1 ThreadPoolDemo.mainpool-1-thread-1
- newCachedThreadPool
该方法返回一个可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线程可以复用,则会优先使用可复用的
线程。若所有线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务执行完毕后,将返回线程池进行复用。
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
executorService.execute(() -> {
System.out.println("ThreadPoolDemo.main" + Thread.currentThread().getName());
Sleep.sleep(500);
});
Sleep.sleep(200);
}
}
结果:
ThreadPoolDemo.mainpool-1-thread-1 ThreadPoolDemo.mainpool-1-thread-2 ThreadPoolDemo.mainpool-1-thread-3 ThreadPoolDemo.mainpool-1-thread-1 ThreadPoolDemo.mainpool-1-thread-2 ThreadPoolDemo.mainpool-1-thread-3 ThreadPoolDemo.mainpool-1-thread-1 ThreadPoolDemo.mainpool-1-thread-2 ThreadPoolDemo.mainpool-1-thread-3 ThreadPoolDemo.mainpool-1-thread-1
- newSingleThreadScheduledExecutor
该方法返回一个ScheduledExecutorService对象,线程池大小为1.ScheduledExecutorService接口在ExecutorService接口之上扩展了在给定时间执行某任务的功能,如在某个固定的延时之后执行,或者周期性执行某个任务。
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
// for (int i = 0; i < 10; i++) {
scheduledExecutorService.scheduleAtFixedRate(() -> {
System.out.println("ThreadPoolDemo.main" + Thread.currentThread().getName() + " : " + System.currentTimeMillis());
}, 0, 2, TimeUnit.SECONDS);
// 创建并执行在给定延迟后启用的一次性操作。
// public ScheduledFuture> schedule(Runnable command, long delay, TimeUnit unit);
// 创建并执行在给定延迟后启用的一次性操作。有返回值
// public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit)
// 创建并执行一个周期性动作,该周期性动作在给定的初始延迟之后首先启用,然后在给定的周期之后启用;即执行将在{@code initialDelay}之后开始,然后是{@code initialDelay+period},然后是{@code initialDelay+ 2 period},以此类推。如果任务的任何执行遇到异常,则后续执行将被抑制。否则,任务只能通过取消或终止执行程序来终止。如果这个任务的执行时间超过了它的周期,那么后续的执行可能会延迟开始,但不会并发执行。
// public ScheduledFuture> scheduleAtFixedRate(Runnable command,long initialDelay, long period, TimeUnit unit);
- newScheduledThreadPool
该方法也返回一个ScheduledExecutorService对象,但该线程池可以指定线程数量。



