1. Java线程池的作用
1. Java线程池的作用
- 降低资源消耗
- 通过重复利用已创建的线程,减少线程创建和销毁带来的开销。线程创建和销毁需要系统分配和回收资源,如内存等。例如,频繁创建和销毁线程的场景中,如果使用线程池,就可以避免每次都进行这些资源的分配和回收操作,从而提高系统的性能和效率。
- 提高响应速度
- 当有任务需要执行时,线程池中的线程可以立即执行任务,而不需要等待线程创建的过程。比如在一个Web服务器中,当有多个客户端请求同时到达时,如果使用线程池,线程池中的线程可以马上处理这些请求,减少客户端的等待时间,提高服务器对请求的响应速度。
- 便于线程管理
- 线程池可以统一管理线程的生命周期、数量等。可以设置线程池中的最大线程数,避免线程过多导致系统资源耗尽。例如,可以根据系统的资源状况和任务的负载情况,合理地配置线程池中的线程数量,同时还可以对线程进行监控和管理,如查看线程的执行状态等。
2. Java线程池的实现方式
- 使用 ThreadPoolExecutor 类
- 构造函数参数
- ThreadPoolExecutor 的构造函数有多个参数,主要包括核心线程数( corePoolSize )、最大线程数( maxPoolSize )、线程存活时间( keepAliveTime )、时间单位( unit )、任务队列( workQueue )、线程工厂( threadFactory )和拒绝策略( handler )。
- 核心线程数是线程池中始终保持的线程数量,即使这些线程处于空闲状态也不会被销毁。最大线程数是线程池允许存在的线程的最大数量。当任务队列已满且线程数量小于最大线程数时,会创建新的线程来执行任务。线程存活时间是指当线程数量超过核心线程数时,多余的空闲线程在等待新任务的时间达到该存活时间后会被销毁。时间单位用于指定线程存活时间的单位。任务队列用于存放等待执行的任务。线程工厂用于创建线程。拒绝策略用于当任务队列已满且线程数量达到最大线程数时,决定如何处理新到来的任务。
- 示例代码
java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExample {
public static void main(String[] args) {
// 创建一个线程池,核心线程数为3,最大线程数为5,线程存活时间为10秒,任务队列使用LinkedBlockingQueue
ExecutorService executorService = new ThreadPoolExecutor(3, 5, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
for (int i = 0; i < 10; i++) {
final int taskId = i;
executorService.execute(() -> {
System.out.println("Task " + taskId + " is being executed by thread " + Thread.currentThread().getName());
});
}
// 关闭线程池
executorService.shutdown();
}
}
- 使用 Executors 工厂类
- Executors 工厂类提供了一些静态方法来创建不同类型的线程池。
- newFixedThreadPool
- 创建一个固定大小的线程池,线程数量固定为指定的值。例如:
java
ExecutorService executorService = Executors.newFixedThreadPool(5);
- 其内部实际上也是使用 ThreadPoolExecutor 类来实现的,只是一些参数已经被默认设置好了。它的核心线程数和最大线程数相等,都等于指定的线程数量,任务队列使用 LinkedBlockingQueue ,没有设置线程存活时间(实际上是 0L ,但由于核心线程数和最大线程数相等,所以不会有线程被销毁),线程工厂使用默认的线程工厂,拒绝策略使用 AbortPolicy (当任务队列已满且线程数量达到最大线程数时,会抛出 RejectedTaskException )。
- newCachedThreadPool
- 创建一个可根据需要创建新线程的线程池。例如:
java
ExecutorService executorService = Executors.newCachedThreadPool();
- 它的核心线程数为 0 ,最大线程数为 Integer.MAX_VALUE ,任务队列使用 SynchronousQueue (一个不存储任务的队列,要求有一个线程来立即执行新到来的任务),线程存活时间为 60 秒,线程工厂使用默认的线程工厂,拒绝策略使用 AbortPolicy 。当有新任务到来时,如果当前没有空闲线程,就会创建一个新线程来执行任务,当线程空闲一段时间( 60 秒)后会被销毁。
- newSingleThreadPool
- 创建一个只有一个线程的线程池。例如:
java
ExecutorService executorService = Executors.newSingleThreadPool();
- 它的核心线程数和最大线程数都为 1 ,任务队列使用 LinkedBlockingQueue ,没有设置线程存活时间(实际上是 0L ,但由于只有一个线程,所以不会有线程被销毁),线程工厂使用默认的线程工厂,拒绝策略使用 AbortPolicy 。所有任务都在这一个线程中依次执行。
- 降低资源消耗
- 通过重复利用已创建的线程,减少线程创建和销毁带来的开销。线程创建和销毁需要系统分配和回收资源,如内存等。例如,频繁创建和销毁线程的场景中,如果使用线程池,就可以避免每次都进行这些资源的分配和回收操作,从而提高系统的性能和效率。
- 提高响应速度
- 当有任务需要执行时,线程池中的线程可以立即执行任务,而不需要等待线程创建的过程。比如在一个Web服务器中,当有多个客户端请求同时到达时,如果使用线程池,线程池中的线程可以马上处理这些请求,减少客户端的等待时间,提高服务器对请求的响应速度。
- 便于线程管理
- 线程池可以统一管理线程的生命周期、数量等。可以设置线程池中的最大线程数,避免线程过多导致系统资源耗尽。例如,可以根据系统的资源状况和任务的负载情况,合理地配置线程池中的线程数量,同时还可以对线程进行监控和管理,如查看线程的执行状态等。
2. Java线程池的实现方式
- 使用 ThreadPoolExecutor 类
- 构造函数参数
- ThreadPoolExecutor 的构造函数有多个参数,主要包括核心线程数( corePoolSize )、最大线程数( maxPoolSize )、线程存活时间( keepAliveTime )、时间单位( unit )、任务队列( workQueue )、线程工厂( threadFactory )和拒绝策略( handler )。
- 核心线程数是线程池中始终保持的线程数量,即使这些线程处于空闲状态也不会被销毁。最大线程数是线程池允许存在的线程的最大数量。当任务队列已满且线程数量小于最大线程数时,会创建新的线程来执行任务。线程存活时间是指当线程数量超过核心线程数时,多余的空闲线程在等待新任务的时间达到该存活时间后会被销毁。时间单位用于指定线程存活时间的单位。任务队列用于存放等待执行的任务。线程工厂用于创建线程。拒绝策略用于当任务队列已满且线程数量达到最大线程数时,决定如何处理新到来的任务。
- 示例代码
java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExample {
public static void main(String[] args) {
// 创建一个线程池,核心线程数为3,最大线程数为5,线程存活时间为10秒,任务队列使用LinkedBlockingQueue
ExecutorService executorService = new ThreadPoolExecutor(3, 5, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
for (int i = 0; i < 10; i++) {
final int taskId = i;
executorService.execute(() -> {
System.out.println("Task " + taskId + " is being executed by thread " + Thread.currentThread().getName());
});
}
// 关闭线程池
executorService.shutdown();
}
}
- 使用 Executors 工厂类
- Executors 工厂类提供了一些静态方法来创建不同类型的线程池。
- newFixedThreadPool
- 创建一个固定大小的线程池,线程数量固定为指定的值。例如:
java
ExecutorService executorService = Executors.newFixedThreadPool(5);
- 其内部实际上也是使用 ThreadPoolExecutor 类来实现的,只是一些参数已经被默认设置好了。它的核心线程数和最大线程数相等,都等于指定的线程数量,任务队列使用 LinkedBlockingQueue ,没有设置线程存活时间(实际上是 0L ,但由于核心线程数和最大线程数相等,所以不会有线程被销毁),线程工厂使用默认的线程工厂,拒绝策略使用 AbortPolicy (当任务队列已满且线程数量达到最大线程数时,会抛出 RejectedTaskException )。
- newCachedThreadPool
- 创建一个可根据需要创建新线程的线程池。例如:
java
ExecutorService executorService = Executors.newCachedThreadPool();
- 它的核心线程数为 0 ,最大线程数为 Integer.MAX_VALUE ,任务队列使用 SynchronousQueue (一个不存储任务的队列,要求有一个线程来立即执行新到来的任务),线程存活时间为 60 秒,线程工厂使用默认的线程工厂,拒绝策略使用 AbortPolicy 。当有新任务到来时,如果当前没有空闲线程,就会创建一个新线程来执行任务,当线程空闲一段时间( 60 秒)后会被销毁。
- newSingleThreadPool
- 创建一个只有一个线程的线程池。例如:
java
ExecutorService executorService = Executors.newSingleThreadPool();
- 它的核心线程数和最大线程数都为 1 ,任务队列使用 LinkedBlockingQueue ,没有设置线程存活时间(实际上是 0L ,但由于只有一个线程,所以不会有线程被销毁),线程工厂使用默认的线程工厂,拒绝策略使用 AbortPolicy 。所有任务都在这一个线程中依次执行。