线程池
初始化线程池的 4 种方式
-
继承 Thread
Thread01 thread = new Thread01(); thread.start() -
实现 Runnable 接口
Runnable01 runnable01 = new Runnable01(); runnable01.start(); -
实现 Callable 接口 + FutureTask( 可以拿到返回结果,可以处理异常)
FutureTask<Integer> futureTask = new FutureTask<>(new Callable01()); new Thread(futureTask).start(); -
线程池的创建
ThreadPoolExecutor executor = new ThreadPoolExecutor( int corePoolSize, //线程池创建好之后,核心线程数[一直存在,除非allowCoreThreadTimeOut], //创建好之后就准备就绪的线程数量,等待接收异步任务来执行 int maximumPoolSize, // 最大线程数量,控制资源 long keepAliveTime, // 存活时间,如果当前线程数量大于核心数量, // 释放空闲的线程 (maximumPoolSize - corePoolSize) // 只要线程空闲时间大于指定的 keepAliveTime TimeUnit unit, // 时间单位 BlockingQueue<Runnable> workQueue, // 阻塞队列,如果任务有很多,就会将目前多的任务放到队列中 // 只要有线程空闲,就会去队列米面取出新的任务继续执行 ThreadFactory threadFactory, // 线程创建的工厂,也可以自定义 RejectedExecutionHandler handler // 如果队列满了,按照指定的拒绝策略,拒绝执行 );其他的创建方式:
-
创建一个可缓存线程池,如果线程次长度超过处理需要,可以灵活回收空闲线程,
若无可回收,则新建线程 核心是 0,所有都可以回收ExecutorService threadPool = Executors.newCachedThreadPool(); -
固定大小 核心线程数 == 最大线程数,都不可以回收的线程池
ExecutorService threadPool = Executors.newFixedThreadPool(3); -
定时任务的线程池
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(3); -
单线程的线程池,后台从队列中获取任务挨个执行 核心线程数 == 最大线程数 == 1
ExecutorService threadPool = Executors.newSingleThreadExecutor();
通过线程池创建,性能稳定,可以获取执行结果,捕获异常。但是,在业务复杂情况下,一个异步调用可能会依赖于另一个异步调用的执行结果
-
-
线程池的工作顺序
-
线程池创建,准备好 core 数量的核心线程,准备接受任务
-
corePoolSize 满了之后,就将再进来的任务放入阻塞队列中。空闲的 corePoolSize 就会自己去阻塞队列获取任务执行
-
阻塞队列满了,就直接开新线程执行,最大只能开到 maximumPoolSize 指定的数量
-
maximumPoolSize 满了之后,就 RejectedExecutionHandler 拒绝任务
-
maximumPoolSize 都执行完成,有很多空闲,在指定的时间 keepAliveTime 以后,释放 maximumPoolSize - corePoolSize 这些线程
-
new BlockingDeque<>(业务订制的数量,压力测试得到) 默认是 Integer 的最大值
面试题:一个线程池: core 7, max 20, queue 50, 100 并发进来怎么分配
7 个立即执行,50 个进入队列,再开启 20-7=13 个进行执行。剩下的 30个使用拒绝策略
如果不想抛弃还要执行,CallerRunsPolicy
-
-
开发中为什么使用线程池
-
降低资源的消耗
通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗 -
提高响应速度
因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,
当任务来时无需创建新的线程就能执行 -
提高线程的可管理性
线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来
的系统开销。无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,
使用线程池进行统一分配
-
-
区别
- 继承 Thread、实现 Runnable 接口无法拿到返回值,实现 Callable 接口可以拿到返回值
- 继承 Thread、实现 Runnable 接口 、实现 Callable 接口 都不能控制资源
- 线程池可以控制资源,性能稳定
CompletableFuture 异步编排
业务场景:查询商品详情页的逻辑比较复杂,有些数据还需要远程调用,必然需要花费更多的时间
1. 获取 sku 的基本信息 0.5s
2. 获取 sku 的图片信息 0.5s
3. 获取 sku 的促销信息 1.0s
4. 获取 spu 的说有销售属性 1.0s
5. 获取规格参数数组及组下的规格参数 1.5s
6. spu 详情 1.0s
加入商品详情页的每个查询,需要如下标注的时间才能完成
那么,用户需要 5.5s 后才能看到商品详情页的内容。很显然是不能接受的
如果有多个线程同时完成这 6 个操作,也许只需要1.5s 即可完成响应
1. 创建异步对象
CompletableFuture 提供了四个静态方法来创建一个异步操作
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier);
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
public static CompletableFuture<Void> runAsync(Runnable runnable);
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
// 1. runAsync 都是没有返回结果的,supplyAsync 是可以获取返回结果的
// 2. 可以传入自定义的线程池,否则就使用默认的线程池
// 当前系统线程池只有一两个,每个异步任务,提交给线程池让他自己去执行
private static ExecutorService executor = Executors.newFixedThreadPool(10);
// 异步任务,无返回值
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println("current thread: " + Thread.currentThread().getId());
int i = 100 / 2;
System.out.println("run result: " + i);
}, executor);
// 异步任务,可以拿到返回值
CompletableFuture<Integer> futureReturn = CompletableFuture.supplyAsync(() -> {
System.out.println("current thread: " + Thread.currentThread().getId());
int i = 100 / 2;
System.out.println("run result: " + i);
return i;
}, executor);
// current thread: 11
// run result: 50
// current thread: 12
// run result: 50
2. 计算完成时回调方法方法完成后的感知
public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action);
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action);
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor);
public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn) {}
-
whenComplete() 可以处理正常和异常的计算结果,exceptionally 处理异常情况。
-
whenComplete 和 whenCompleteAsync() 的区别
a) whenComplete: 是执行当前任务的线程继续执行 whenComplete 的任务
b) whenCompleteAsync: 是执行把 whenCompleteAsync 这个任务继续交给线程池方法不以 Async 结尾,意味着使用相同的线程执行,而以Async结尾 可能会使用其他的线程执行(如果是使用相同的线程池,也可能被同一个线程选中执行)
// 异步任务,可以拿到返回值
CompletableFuture<Integer> futureReturn = CompletableFuture.supplyAsync(() -> {
System.out.println("current thread: " + Thread.currentThread().getId());
int i = 100 / 0;
System.out.println("run result: " + i);
return i;
}, executor).whenComplete((res, exception) -> {
// 虽然能得到异常信息,但没法修改返回的数据
System.out.println("The asynchronous task succeeded....turns out : " + res);
System.out.println("The asynchronous task succeeded....exception is : " + exception);
}).exceptionally(throwable -> {
// 可以感知异常,同时返回默认值
System.out.println("Abnormal condition");
return 10;
});
System.out.println("" + futureReturn.get());
// current thread: 11
// The asynchronous task succeeded....turns out : null
// The asynchronous task succeeded....exception is : java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
// Abnormal condition
// 10
3.handle() 方法 可以修改返回结果
public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor);
// 方法执行完成后的处理
CompletableFuture<Integer> futureReturn = CompletableFuture.supplyAsync(() -> {
System.out.println("current thread: " + Thread.currentThread().getId());
int i = 100 / 2;
System.out.println("run result: " + i);
return i;
}, executor).handle((res, throwable)->{
if(res != null) return res * 2;
if(throwable != null) return 0;
return 0;
});
System.out.println(futureReturn.get());
// current thread: 11
// run result: 50
// 100
4 线程串行化方法
// thenApply 方法: 当一个线程依赖另一个线程时,获取上一个任务返回的额结果,并返回任务的返回值
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn);
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn);
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor);
// thenAccept 方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果
public CompletableFuture<Void> thenAccept(Consumer<? super T> action);
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action);
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor);
// thenRun 方法:只要上面的任务执行完成,就可以执行 thenRun, 只是处理完任务后,thenRun 的后续操作
public CompletableFuture<Void> thenRun(Runnable action);
public CompletableFuture<Void> thenRunAsync(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action, Executor executor);
thenRun
// 线程串行化
// 1) thenRun: 无法获取上一步的执行结果, 无返回值
// thenRun(() -> {
// System.out.println("Thread2 run...");
// });
//
CompletableFuture<Void> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("current thread: " + Thread.currentThread().getId());
int i = 100 / 2;
System.out.println("run result: " + i);
return i;
}, executor).thenRun(() -> {
System.out.println("Thread2 run...");
});
// 线程串行化
// 2) thenAccept: 可以获取上一步的执行结果, 无返回值
// thenAccept((res) -> {
// System.out.println("Thread2 run..." + res);
// });
//
CompletableFuture<Void> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("current thread: " + Thread.currentThread().getId());
int i = 100 / 2;
System.out.println("run result: " + i);
return i;
}, executor).thenAccept((res) -> {
System.out.println("Thread2 run..." + res);
});
// 线程串行化
// 3) thenApply 可以获取到上一步的返回结果,并修改上一步的返回结果
// thenApply(res -> {
// System.out.println("Thread2 run... " + res);
// return Math.sqrt(res);
// });
CompletableFuture<Double> future3 = CompletableFuture.supplyAsync(() -> {
System.out.println("current thread: " + Thread.currentThread().getId());
int i = 100 / 2;
System.out.println("run result: " + i);
return i;
}, executor).thenApply(res -> {
System.out.println("Thread2 run... " + res);
return Math.sqrt(res);
}, executor);
5. 两任务组合
- thenCombine
// thenCombine: 组合两个 future,获取两个 future 的返回结果,并返回当前任务的返回值
public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn, Executor executor);
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("future01 start: " + Thread.currentThread().getId());
int i = 100 / 2;
System.out.println("future01 start: " + i);
return i;
}, executor);
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("future02 start: " + Thread.currentThread().getId());
System.out.println("future02 start: ");
return "Hello";
}, executor);
future01.runAfterBothAsync(future02, () -> {
System.out.println("future03 start: " + Thread.currentThread().getId());
System.out.println("future03 start: ");
}, executor);
- thenAcceptBoth
// thenAcceptBoth: 组合两个 future,获取两个 future 的返回结果,然后处理任务,没有返回值
public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action);
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action);
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action, Executor executor);
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("future01 start: " + Thread.currentThread().getId());
int i = 100 / 2;
System.out.println("future01 start: " + i);
return i;
}, executor);
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("future02 start: " + Thread.currentThread().getId());
System.out.println("future02 start: ");
return "Hello";
}, executor);
future01.thenAcceptBothAsync(future02, (f1, f2) -> {
System.out.println("f1 = " + f1);
System.out.println("f2 = " + f2);
}, executor);
// 运行结果:
//future01 start: 11
//future01 start: 50
//future02 start: 12
//future02 start:
//f1 = 50
//f2 = Hello
- runAfterBoth
// runAfterBoth: 组合两个 future,不需要获取 future 的结果,只需两个future 处理完任务后,处理该任务
public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other, Runnable action);
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action);
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action, Executor executor);
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("future01 start: " + Thread.currentThread().getId());
int i = 100 / 2;
System.out.println("future01 start: " + i);
return i;
}, executor);
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("future02 start: " + Thread.currentThread().getId());
System.out.println("future02 start: ");
return "Hello";
}, executor);
CompletableFuture<String> futureRes = future01.thenCombineAsync(future02, (f1, f2) -> {
System.out.println("f1 = " + f1);
System.out.println("f2 = " + f2);
System.out.println("self data = " + f1 + ", " + f2);
return "self data = " + f1 + ", " + f2;
}, executor);
System.out.println("final result = " + futureRes.get());
// future01 start: 11
// future01 start: 50
// future02 start: 12
// future02 start:
// f1 = 50
// f2 = Hello
// self data = 50, Hello
// final result = self data = 50, Hello
6.两任务组合,一个完成
- runAfterEither 两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返回值
public CompletableFuture<Void> runAfterEither(CompletionStage<?> other, Runnable action);
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action);
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action, Executor executor);
代码示例:
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("future01 start: " + Thread.currentThread().getId());
int i = 100 / 2;
System.out.println("future01 end: " + i);
return i;
}, executor);
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("future02 start: " + Thread.currentThread().getId());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("future02 end: ");
return "Hello";
}, executor);
// runAfterEitherAsync: 两个任务只要有一个完成,就执行任务3
// 两个任务,只要有一个完成,就执行任务3
future01.runAfterEitherAsync(future02, ()->{
System.out.println("future03 start: " + Thread.currentThread().getId());
}, executor);
// future01 start: 11
// future01 end: 50
// future02 start: 12
// future03 start: 13
// future03 end: 13
// future02 end:
- acceptEither 两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值
public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action);
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action);
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action, Executor executor);
代码示例:
CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("future01 start: " + Thread.currentThread().getId());
int i = 100 / 2;
System.out.println("future01 end: " + i);
return i;
}, executor);
CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("future02 start: " + Thread.currentThread().getId());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("future02 end: ");
return "Hello";
}, executor);
future01.acceptEitherAsync(future02, (res)->{
System.out.println("future03 start: " + Thread.currentThread().getId());
System.out.println("get result : " + res);
System.out.println("future03 end: " + Thread.currentThread().getId());
}, executor);
// future01 start: 11
// future01 end: 50
// future02 start: 12
// future03 start: 13
// get result : 50
// future03 end: 13
// future02 end:
- applyToEither 两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值
public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn);
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn);
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn, Executor executor);
代码示例
CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("future01 start: " + Thread.currentThread().getId());
int i = 100 / 2;
System.out.println("future01 end: " + i);
return i;
}, executor);
CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("future02 start: " + Thread.currentThread().getId());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("future02 end: ");
return "Hello";
}, executor);
CompletableFuture<String> async = future01.applyToEitherAsync(future02, (res) ->{
System.out.println("future03 start: " + Thread.currentThread().getId());
System.out.println("future03 end: " + Thread.currentThread().getId());
return res + "hahaha";
}, executor);
System.out.println("modified result : " + async.get());
// future01 start: 11
// future01 end: 50
// future02 start: 12
// future03 start: 13
// future03 end: 13
// modified result : 50hahaha
// future02 end:
7. 多任务组合
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs);
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs);
- allOf:等待所有任务完成
- anyOf:只要有一个任务完成
allOf 示例代码
CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
System.out.println("Query the picture information of a product");
return "hello.jpg";
}, executor);
CompletableFuture<String> futureAttribute = CompletableFuture.supplyAsync(() -> {
System.out.println("Query the attribute information of a product");
return "black + 256GB";
}, executor);
CompletableFuture<String> futureDescription = CompletableFuture.supplyAsync(()->{
System.out.println("Query the description information of a product");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hua Wei";
}, executor);
CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttribute, futureDescription);
allOf.get(); // 等待全部都执行完成
// 拿到各自的结果
System.out.println(futureImg.get());
System.out.println(futureAttribute.get());
System.out.println(futureDescription.get());
// future02 start: 12
// Query the picture information of a product
// future01 start: 11
// future01 end: 50
// Query the attribute information of a product
// Query the description information of a product
// future02 end:
// hello.jpg
// black + 256GB
// Hua Wei
anyOf
CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
System.out.println("Query the picture information of a product");
return "hello.jpg";
}, executor);
CompletableFuture<String> futureAttribute = CompletableFuture.supplyAsync(() -> {
System.out.println("Query the attribute information of a product");
return "black + 256GB";
}, executor);
CompletableFuture<String> futureDescription = CompletableFuture.supplyAsync(()->{
System.out.println("Query the description information of a product");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hua Wei";
}, executor);
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttribute, futureDescription);
anyOf.get(); // 等待全部都执行完成
// future02 start: 12
// future01 start: 11
// future01 end: 50
// Query the picture information of a product
// Query the attribute information of a product
// Query the description information of a product
// future02 end:
1999

被折叠的 条评论
为什么被折叠?



