Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池,所以我们就要认识并弄懂线程池,以便于更好的为我们业务场景服务。
一、为什么使用线程池
在web开发中,服务器需要接受并处理请求,所以会为一个请求来分配一个线程来进行处理。如果每次请求都新创建一个线程的话实现起来非常简便,但是如果并发的请求数量非常多,但每个线程执行的时间很短,这样就会频繁的创建和销毁线程,大大降低系统的效率。导致服务器在为每个请求创建新线程和销毁线程上花费的时间和消耗的系统资源要比处理实际的用户请求的时间和资源更多。
线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后启动给这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。线程池为线程生命周期的开销和资源不足问题提供了解决方案。通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。
二、线程池的好处
- 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
- 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
- 提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,
还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控(根据系统承受能力,达到运行的最佳效果),避免无限创建线程引起的OutOfMemoryError (OOM)。
三、线程池工作流程
-
当提交一个新任务到线程池时,线程池判断corePoolSize线程池是否都在执行任务,如果有空闲线程,则从核心线程池中取一个线程来执行任务,直到当前线程数等于corePoolSize ; -
如果当前线程数为corePoolSize ,继续提交的任务被保存到阻塞队列中,等待被执行; -
如果阻塞队列满了,那就创建新的线程执行当前任务,直到线程池中的线程数达到maxPoolSize ,这时再有任务来,由饱和策略来处理提交的任务
四、创建线程池
import java.util.concurrent.*;
public class ThreadPool {
public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
for (int i = 0; i < 2; i++) {
executorService.execute(() -> {
System.out.println(Thread.currentThread().getName() + "——" + "办理业务");
});
}
executorService.shutdown();
}
}
五、线程池参数
下面是ThreadPoolExecutor类的构造方法传参数:
corePoolSize : 线程池核心线程数最大值maximumPoolSize : 线程池最大线程数大小keepAliveTime : 线程池中非核心线程空闲的存活时间大小TimeUnit : 线程空闲存活时间单位workQueue : 存放任务的阻塞队列threadFactory : 用于设置创建线程的工厂,可以给线程设置名字,方便排查问题handler : 线城池的饱和策略事件,主要有四种类型。
感谢大家的耐心阅读,如有建议请私信或评论留言
|