概念
线程池实际上是一个维护很多线程的池。 类似的池化技术还有很多,比如:连接池、数据库连接池、内存池等。
线程池的优点
Java并发编程框架中的线程池是应用最广泛的技术。 几乎所有需要异步或并发执行任务的程序都可以使用线程池。 在开发过程中,合理使用线程池至少可以带来以下四个好处:
减少资源消耗。 通过复用已创建的线程,减少线程创建和销毁带来的消耗; 提高响应速度。 当任务到达时,可以立即执行任务,无需等待线程创建,提高线程的可管理性。 线程是稀缺资源。 如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性。 线程池可用于统一分配、调优和监控。 提供更强大的功能。例如延迟定时线程池; 线程池的实现原理
当用户向线程池提交任务时,线程池会这样执行:
首先判断核心线程数是否满。 如果未满,则创建一个线程来执行任务; 如果线程池中的核心线程数已满,则继续判断任务队列是否已满。 如果未满,则将任务放入任务队列即可。 如果任务队列已满,则判断线程池是否已满。 如果未满,则创建一个线程来执行任务; 如果线程池已满,则根据拒绝策略做出决定。 对应加工等级
在我们的日常开发中,线程池的使用基本上都是基于类的。 它的继承体系是这样的:
-> 冰->->
施工方法
public class ThreadPoolExecutor extends AbstractExecutorService {
......
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0){
throw new IllegalArgumentException();
}
if (workQueue == null || threadFactory == null || handler == null){
throw new NullPointerException();
}
this.acc = System.getSecurityManager() == null ? null : AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
}
主要参数如下:
:线程池工厂,主要用于给线程一个标识。 即给线程起一个有意义的名字;
: 拒绝政策
提交任务到线程池
向线程池提交任务有两种方法,分别是 和 。
方法
()方法用于提交不需要返回值的任务,因此无法判断任务是否被线程池成功执行。
()方法输入的任务是一个类的实例。
空白 ( );
executorService.execute(()->{
System.out.println("ThreadPoolDemo.execute");
});
方法
()方法用于提交需要返回值的任务。
(任务);
线程池会返回一个类型的对象,通过该对象可以判断任务是否执行成功,并可以通过get()方法获取返回值。 get()方法会阻塞当前线程直到任务完成,而使用get(long,unit)方法会阻塞当前线程一段时间并立即返回。 这个时候,任务可能还没有完成。
Future<?> submit = executorService.submit(() -> {
System.out.println("ThreadPoolDemo.submit");
});
关闭线程池
通过调用线程池的 or 方法关闭线程池
它们的原理是遍历线程池中的工作线程,然后一一调用线程方法来中断线程(PS:中断只是标记线程,并不代表线程已经停止,如果线程没有停止)响应中断,则该标记将不起作用),因此无法响应中断的任务可能永远不会终止。
但它们之间也存在一定的差异。 首先将线程池的状态设置为STOP,然后尝试停止所有正在执行或挂起任务的线程,并返回等待执行的任务列表,但只需将线程池的状态设置为,然后中断所有未执行任务的线程。
只要调用这两个关闭方法中的任何一个,该方法都会返回 true。 当所有任务都已经关闭后,就表示线程池关闭成功,调用方法会返回true。 至于应该调用哪个方法来关闭线程池,应该根据提交到线程池的任务的特性来确定。 通常会调用一个方法来关闭线程池。 如果任务不必完成,则可以调用一个方法。
线程池状态 线程池有5种状态,STOP, , ,
3. 状态说明
为线程池设置合理的参数
设置参数一般取决于以下几点:
不同性质的任务可以使用不同大小的线程池分别处理。 分为CPU密集型和IO密集型。
类创建线程池
它是Java中的一个工具类。 提供工厂方法来创建不同类型的线程池。
(int):创建一个固定线程数的线程池。 ():创建一个可缓存的线程池,调用将重用之前构造的线程(如果线程可用)。 如果没有可用线程,则会创建一个新线程并将其添加到池中。 终止并从缓存中删除那些 60 秒未使用的线程。 tor() 创建一个单线程。 ol(int) 创建一个支持计划和周期性任务执行的线程池,在大多数情况下可以用来替换 Timer 类。
该类看上去功能比较强大,采用工厂模式,扩展性比较强。 重要的是使用起来比较方便,比如:
=.();
创建线程池的问题
阿里巴巴Java开发手册中明确规定,不允许创建线程池。
使用ol运行时创建的线程数是。 可能会创建大量线程,导致OOM总结
线程池执行图
补充一下常用的队列,线程池中常用的方法有,队列如下: