1线程池ThreadPoolExecutor
线程池:三大方式、七大参数、四种拒绝策略
池化技术:池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率。线程池、JDBC的连接池、内存池、对象池 等等;资源的创建、销毁十分消耗资源
线程池的好处:
1、降低资源的消耗;
2、提高响应的速度;
3、方便管理;
线程复用、可以控制最大并发数、管理线程
1线程池有哪几种创建方式?
(1)newSingleThreadExecutor:创建一个单线程的线程池。
(2)newFixedThreadPool:创建固定大小的线程池。
(3)newCachedThreadPool:创建一个可缓存的线程池。
(4)newScheduledThreadPool:创建一个大小无限的线程池。
2线程池都有哪些状态?
RUNNING:这是最正常的状态,接受新的任务,处理等待队列中的任务。
SHUTDOWN:不接受新的任务提交,但是会继续处理等待队列中的任务。
STOP:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。
TIDYING【tidying】:所有的任务都销毁了,workCount 为 0,线程池的状态在转换为 TIDYING 状态时,会执行子方法 terminated()。
TERMINATED:terminated()方法结束后,线程池的状态就会变成这个。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//工具类 Executors 三大方法;
public class Test {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程
ExecutorService threadPool2 = Executors.newFixedThreadPool(5); //创建一个固定的线程池的大小
ExecutorService threadPool3 = Executors.newCachedThreadPool(); //可伸缩的
//线程池用完必须要关闭线程池
try {
for (int i = 1; i <=10 ; i++) {
//通过线程池创建线程
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+ " ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
}
3创建线程池的七大参数
```java
public ThreadPoolExecutor(int corePoolSize, //核心线程池大小,线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,他们也不会被销毁。
int maximumPoolSize, //一个任务被提交到线程池以后,首先会找有没有空闲存活线程,如果有则直接将任务交给这个空闲线程来执行,
//如果没有则会缓存到工作队列( BlockingQueue<Runnable> workQueue)中
//如果工作队列满了,才会创建一个新线程,然后从工作队列的头部取出一个任务交由新线程来处理,而将刚提交的任务放入工作队列尾部。线程池不会无限制的去创建新线程,
//它会有一个最大线程数量的限制,这个数量即由maximunPoolSize指定。
long keepAliveTime, //一个线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,这个空闲线程会被销毁
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.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
4Executors 各个方法的弊端:
阿里巴巴的Java操作手册中明确说明:对于Integer.MAX_VALUE初始值较大,所以一般情况我们要使用底层的ThreadPoolExecutor来创建线程池。
5你知道怎么创建线程池吗?
ThreadPoolExecutor() 是最原始的线程池创建,也是阿里巴巴 Java 开发手册中明确规范的创建线程池的方式。
public class Test {
public static void main(String[] args) {
// 获取cpu 的核数
int max = Runtime.getRuntime().availableProcessors();
ExecutorService service =new ThreadPoolExecutor(
2,
max,
3,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
try {
for (int i = 1; i <= 10; i++) {
service.execute(() -> {
System.out.println(Thread.currentThread().getName() + "ok");
});
}
}catch (Exception e) {
e.printStackTrace();
}
finally {
service.shutdown();
}
}
}
4拒绝策略
ThreadPoolExecutor 拒绝策略定义: 如果当前同时运行的线程数量达到最大线程数量并且队列也已经被放满了任务时;
- new ThreadPoolExecutor.AbortPolicy(): //该拒绝策略为:拒绝新任务的处理,并抛出异常—超出最大承载,就会抛出异常;最大承载=maximumPoolSize + BlockingQueue
- new ThreadPoolExecutor.CallerRunsPolicy(): //该拒绝策略为:调用执行自己的线程运行任务 哪来的去哪里 main线程进行处理
- new ThreadPoolExecutor.DiscardPolicy(): //该拒绝策略为:不处理新任务,直接丢弃掉。
- new ThreadPoolExecutor.DiscardOldestPolicy(): //该拒绝策略为**:队列满了,尝试去和最早的进程竞争**,不会抛出异常
4如何设置线程池的大小
1、CPU密集型:电脑的核数是几核就选择几;选择maximunPoolSize的大小
// 获取cpu 的核数
int max = Runtime.getRuntime().availableProcessors();
ExecutorService service =new ThreadPoolExecutor(
2,
max,
3,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
2、I/O密集型:在程序中有15个大型任务,io十分占用资源;I/O密集型就是判断我们程序中十分耗I/O的线程数量,大约是最大I/O数的一倍到两倍之间。