1.线程池详解
1.线程池的作用
2.线程池的创建方式
- newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
- newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
- newScheduledThreadPool 创建一个可定期或者延时执行任务的定长线程池,支持定时及周期性任务执行。
- newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
3.线程池7个核心参数
-
int corePoolSize, 核心线程大小 线程池创建时,就初始化的线程数量
-
int maximumPoolSize,最大线程大小
-
long keepAliveTime, 超过corePoolSize的线程多久不活动被销毁时间 就是除核心线程外的线程,过了这段时间还是空闲就销毁
-
TimeUnit unit,时间单位 上面那参数的单位
-
BlockingQueue workQueue 任务队列 当任务数超过核心线程数时,多出的那些线程会放在任务队列中等待,若任务队列也满了,那么才创建非核心线程来执行
-
ThreadFactory threadFactory 线程池工厂 用来生产线程的,下面是默认的线程工场的代码,代码少我才贴的,大致就做了给创建的线程分组,命名,然后优先级都设置成了 5
-
RejectedExecutionHandler handler 拒绝策略 啥时候要拒绝呢,就是当队列+最大线程数都满足不了任务的执行时,多出来的任务没地放也没地执行的时候,这个时候我们需要舍弃了,是舍弃最开始运行的那几个线程呢,还是后面多出的线程呢,舍弃时抛异常还是不抛异常呢?主要就是如下前四种,默认是第一种Abort,舍弃后面来的多余的任务并抛异常,CallerRun是直接调用这些任务的run方法来执行,我也不抛弃你们,一起执行就完事了,DiscardOldest呢就是抛弃最早执行的那几个,也就是把前浪拍死在沙滩上,Discard呢也是舍弃后面多余的,但是不抛异常.
4.4种线程池创建方式的使用场景
-
newCachedThreadPool:
- 底层:返回ThreadPoolExecutor实例,corePoolSize为0;maximumPoolSize为Integer.MAX_VALUE;keepAliveTime为60L;时间单位TimeUnit.SECONDS;workQueue为SynchronousQueue(同步队列)
- 通俗:当有新任务到来,则插入到SynchronousQueue中,由于SynchronousQueue是同步队列,因此会在池中寻找可用线程来执行,若有可以线程则执行,若没有可用线程则创建一个线程来执行该任务;若池中线程空闲时间超过指定时间,则该线程会被销毁。
- 适用:执行很多短期的异步任务
-
newFixedThreadPool:
- 底层:返回ThreadPoolExecutor实例,接收参数为所设定线程数量n,corePoolSize和maximumPoolSize均为n;keepAliveTime为0L;时间单位TimeUnit.MILLISECONDS;WorkQueue为:new LinkedBlockingQueue() 无界阻塞队列
- 通俗:创建可容纳固定数量线程的池子,每个线程的存活时间是无限的,当池子满了就不再添加线程了;如果池中的所有线程均在繁忙状态,对于新任务会进入阻塞队列中(无界的阻塞队列)
- 适用:执行长期任务
-
newSingleThreadExecutor:
- 底层:FinalizableDelegatedExecutorService包装的ThreadPoolExecutor实例,corePoolSize为1;maximumPoolSize为1;keepAliveTime为0L;时间单位TimeUnit.MILLISECONDS;workQueue为:new LinkedBlockingQueue() 无解阻塞队列
- 通俗:创建只有一个线程的线程池,当该线程正繁忙时,对于新任务会进入阻塞队列中(无界的阻塞队列)
- 适用:按顺序执行任务的场景
-
NewScheduledThreadPool:
- 底层:创建ScheduledThreadPoolExecutor实例,该对象继承了ThreadPoolExecutor,corePoolSize为传递来的参数,maximumPoolSize为Integer.MAX_VALUE;keepAliveTime为0;时间单位TimeUnit.NANOSECONDS;workQueue为:new DelayedWorkQueue() 一个按超时时间升序排序的队列
- 通俗:创建一个固定大小的线程池,线程池内线程存活时间无限制,线程池可以支持定时及周期性任务执行,如果所有线程均处于繁忙状态,对于新任务会进入DelayedWorkQueue队列中,这是一种按照超时时间排序的队列结构
- 适用:执行周期性任务
2.CompletableFuture使用
1.创建异步对象
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
int n = 10 / 2;
System.out.println("我没返回值,Thread-" + Thread.currentThread() + "中输出:" + n);
});
Thread.sleep(100);
CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
int n = 10 / 2;
System.out.println("我有返回值,Thread-" + Thread.currentThread() + "中输出:" + n);
return n;
});
System.out.println("我的返回值是:"+integerCompletableFuture.get());
}
2…完成回调与异常的感知
whenComplete是在调用者前面任务执行完后继续执行内容,可以获取前面任务的返回结果与捕获的异常,当然异常了返回结果一般都是null,exceptionally是捕获异常并且回调方法,来返回新的结果
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
int n = 10 / 0;
System.out.println("我有返回值,Thread-" + Thread.currentThread() + "中输出:" + n);
return n;
}).whenCompleteAsync((res,exception)->{
System.out.println("res:"+res+" exception:"+exception.getMessage());
}).exceptionally((throwable)->{
return 0;
});
System.out.println("返回结果:"+integerCompletableFuture.get());
}
3.handle最终处理
// 有异常时
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
int n = 10 / 0;
System.out.println("我有返回值,Thread-" + Thread.currentThread() + "中输出:" + n);
return n;
}).handle((res,exception) ->{
if(res != null){
res = res*2;
}
if(exception != null){
res = 0;
}
return res;
});
System.out.println("返回结果:"+integerCompletableFuture.get());
}
// 没异常时
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
int n = 10 / 2;
System.out.println("我有返回值,Thread-" + Thread.currentThread() + "中输出:" + n);
return n;
}).handle((res,exception) ->{
if(res != null){
res = res*2;
}
if(exception != null){
res = 0;
}
return res;
});
System.out.println("返回结果:"+integerCompletableFuture.get());
}
4.线程串行化
5.两任务组合,都要完成
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Object> integerCompletableFuture1 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务一执行中...");
int n = 10 / 2;
System.out.println("任务一执行结束");
return n;
});
CompletableFuture<Object> integerCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务二执行中...");
int n = 5 / 2;
System.out.println("任务二执行结束.");
return n;
});
CompletableFuture<String> objectCompletableFuture = integerCompletableFuture1.thenCombine(integerCompletableFuture2, (r1, r2) -> {
String r3 = "";
System.out.println("任务三执行中");
r3 += r3+r1+","+r2;
System.out.println("任务三执行结束");
return r3;
});
System.out.println("任务三返回结果:"+objectCompletableFuture.get());
}
6.两任务组合,一个完成
7.多任务组合
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Object> integerCompletableFuture1 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务一查询商品图片执行中...");
System.out.println("任务一执行结束");
return "huawei121.jpg";
});
CompletableFuture<Object> integerCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务二查询商品属性执行中...");
System.out.println("任务二执行结束.");
return "256G+黑色";
});
CompletableFuture<Object> integerCompletableFuture3 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务二查询商品品牌执行中...");
System.out.println("任务二执行结束.");
return "华为";
});
CompletableFuture<Void> completableFuture = CompletableFuture.allOf(integerCompletableFuture1, integerCompletableFuture2, integerCompletableFuture3);
//此方法会阻塞式等待,直到三个方法都执行完
completableFuture.get();
System.out.println("main线程结束...");
}