文章目录
前言
- 使用线程池的背景
经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。 - 解决上述问题的思路
提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。 - 线程池好处
1) 提高响应速度
2) 降低资源消耗
3) 便于线程管理
实现步骤
- 创建一个线程池服务
ExecutorService:真正的线程池接口,常见子类为ThreadPoolExecutor。
Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池
// 参数: 核心线程数,最大线程数、线程存活时间,存活时间的单位,等待队列,线程工厂(创建线程对象),拒绝策略
ExecutorService service = new ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler);
- 自定义一个线程类,并执行该线程体
service.execute(new MyThread()); // MyThread为自定义线程类
- 使用结束后,关闭服务
service.shutdown();
代码——仿真银行窗口办理业务
-
示例:
假设,某家银行,有5个业务窗口A/B/C/D/E,当前开放3个业务窗口A/B/C用于办理业务,可排队等待办理业务的座位数为3个。
1)当来1/2/3个人时,可选择3个开放的窗口办理业务。
2)当来4/5/6个人时,需在座位上等待前面的人办理结束,之后才能去窗口办理。
3)当来7个人时,银行觉得目前办理人数较多,将办理窗口D也开放用于办理业务。
4)当来8个人时,银行觉得目前办理人数较多,将办理窗口E也开放用于办理业务。
5)由于该银行最大能接受8个人办理业务(在窗口办理业务人数+座位等待人数),因此当第9/10/11等等个人来时,银行将拒绝他们办理业务。
6)当前人数若不足7/8人时,因业务繁忙而开放的窗口D/E将会关闭。 -
代码实现:
下述代码中创建一个办理业务的服务,其中:
核心线程数corePoolSize即为当前开放的三个窗口;
最大线程数maximumPoolSize即为银行的所有业务窗口;
线程存活时间keepAliveTime即为窗口D/E存在时间;
存活时间的单位TimeUnit unit;
等待队列workQueue即为等待座位,需设定其长度;
线程工厂ThreadFactory threadFactor用于创建线程对象:
拒绝策略ThreadPoolExecutor.方法名()即为步骤5)中银行拒绝办理业务。
public class TestPool1 {
public static void main(String[] args) {
// 1. 创建一个服务
// 参数: 核心线程数,最大线程数、线程存活时间,存活时间的单位,等待队列,线程工厂(创建线程对象),拒绝策略(抛异常)
ExecutorService service = new ThreadPoolExecutor(3, 5, 1, TimeUnit.SECONDS,new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
// 2. 执行
for (int i = 0; i < 10; i++) {
service.execute(() -> {
System.out.println(Thread.currentThread().getName() + "办理业务");
});
}
// 3. 关闭服务
service.shutdown();
}
}