一、线程回顾
1、初始化线程的4种方式
1. 继承Thread
Thread01 thread = new Thread01();
thread.start(); //启动线程```
2. 实现Runnable接口
Runnable01 runnable01 = new Runnable01();
new Thread(runnable01).start();
3. 实现Callable接口+FutureTask
FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
new Thread(futureTask).start();//阻塞等待整个线程执行完成,获取返回结果
Integer integer = futureTask.get();
4. 线程池
给线程池直接提交任务。
- 1、创建:
- 1)、Executors
- 2)、new ThreadPoolExecutor
区别:1,2不能得到返回值,3可以获取返回值
1,2,3都不能控制资源
4可以控制资源,性能稳定
实现方式:
Executors.newFiexedThreadPool(3);
//或者
new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit unit, workQueue, threadFactory, handler)
通过线程池性能稳定,也可以获取执行结果,并捕获异常,但是。在业务复杂情况下,一个异步调用可能会依赖于另一个异步调用的执行结果。
* * *
2、线程池的七大参数
ThreadPoolExecutor
1. corePoolSize:[5]核心线程数[一直存在];线程池,创建好以后就准备就绪的线程数量,就等待来接受异步任务去执行* 5个 Thread thread = new Thread();
2. maximumPoolSize[200]:最大线程数量;控制资源
3. keepAliveTime:存活时间。如果当前的线程数量大于core数量,释放空闲的线程(maximumPoolSize-corePoolSize)。只要线程空闲大于指定的keepAliveTime;
4. unit:时间单位
5. BlockingQueue<Runnable> workQueue:阻塞队列。如果任务有很多,就会将目前多的任务放在队列里面。只要有线程空闲,就会取队列里取出新的任务继续
6. threadFactory:线程的创建工厂。
7. RejectedExecutionHandler handler:如果队列满了,按照我们指定的拒绝策略拒绝执行任务。
运行流程:
1. 线程池创建,准备好core数量的核心线程,准备接受任务
2. 新的任务进来,用core准备好的空闲线程执行。
- core满了,就将再进来的任务放入阻塞队列中。空闲的core就会自己去阻塞队列获取任务执行
- 阻塞队列满了,就直接开线程执行,最大只能开到max指定的数量
- max都执行好了,Max-core数量空闲的线程会在keepAliveTime指定的时间后自动销毁,最终保持到core大小。
- 如果线程开到了max的数量,还有新任务进来,就会使用reject指定的拒绝策略进行处理
3. 所有线程创建都是由指定的factory创建的。
面试:
一个线程池 core7;max20 queue:50, 100 并发进来怎么分配的;
先有7个能直接得到执行,接下来50个进入队列排队,在多开13个继续执行。现在70个被安排上了,剩下30个默认拒绝策略。
3、常见的4种线程池
1. Executors.newCachedThreadPool() core是0,所有都可回收
2. Executors.newFixedThreadPool() 固定大小,core=max; 都不可回收
3. Executors.newScheduledThreadPool() 定时任务的线程池
4. Executors.newSingleThreadExecutor() 单线程的线程池,后台队列里面获取任务,挨个执行
二、CompletableFuture 异步编排
1、创建异步对象
CompletableFuture 提供了四个静态方法来创建一个异步操作。
- static CompletableFuture<Void> runAsync (Runnable runnable)
- public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
- public static <U> CompletableFuture<U> supplyAsync(Supplier<U> suppiler)
- public static <U> CompletableFuture<U> supplyAsync(Suppiler<U> suppiler, Executor executor)
1、runXxxx都是没有返回结果的,supplyXxx都是可以获取返回结果的
2、可以传入自定义的线程池,否则就用默认的线程池。
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> { System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);}, executorService);
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<Function<Throwable, ? extends T> fn)
whenComplete可以处理正常和异常的计算结果,exceptionally 处理异常情况。
whenComplete和whenCompleteAsync的区别:
whenComplete:是执行当前任务的线程执行继续执行whenComplete的任务。
whenCompleteAsync:是执行把whenCompleteAsync这个任务继续提交给线程池来进行执行。
方法不以Async结尾,意味着Action使用相同的线程执行,而Async可能会使用其他线程执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 0; System.out.println("运行结果:" + i);
return i;}, executorService).whenComplete((res,exc)->{
System.out.println("异步任务成功完成了...结果是:" + res + ";异常是:" + exc);}).exceptionally(throwable -> { return 10;});
3、handle方法
- public <U> completionStage<U> handle(BiConsumer<? super T, Throwable, ? extends U> fn)
- public <U> completionStage<U> handleAsync(BiConsumer<? super T, Throwable, ? extends U> fn)
- public <U> completionStage<U> handleAsync(BiConsumer<? super T, Throwable, ? extends U> fn, Executor executor)
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> { System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 0; System.out.println("运行结果:" + i);
return i;}, executorService).handle((res,thr)->{
if(res != null){
return res * 2;
}
if(thr != null){
return 0;
}
return 0;});
4、线程串行化方法
- 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)
- public <U> completionStage<U> thenAccept(Consumer<? super T> action)
- public <U> completionStage<U> thenAcceptAsync(Consumer<? super T> action)
- public <U> completionStage<U> thenAcceptAsync(Consumer<? super T> action, Executor executor)
thenApply方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前任务的返回值
thenAcctpt方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果。
thenRun方法:只要上面的任务执行完成,就开始执行thenRun, 只是处理完任务后,执行thenRun的后续操作
thenRun 的后续操作
带有Async默认是异步执行的。同之前。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 4;
System.out.println("运行结果:" + i);
return i;}, executorService).thenApplyAsync(res -> {
System.out.println("任务2启动了" + res);
return "Hello" + res;}, executorService);
5、两任务组合-都要完成
- 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)
- public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other, BiFunction<? super T, ? super U action)
- public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiFunction<? super T, ? super U> action)
- public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiFunction<? super T, ? super U> action, Executor executor)
- public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other, Runnable action)
- public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action)
两个任务必须都完成,触发该任务
CompletableFuture<Integer> future01 =CompletableFuture.supplyAsync(() -> {
System.out.println("任务1线程:" + Thread.currentThread().getId());
int i = 10 / 4;
System.out.println("任务1结束:");
return i;
}, executorService);
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> { System.out.println("任务2线程:" + Thread.currentThread().getId()); System.out.println("任务2结束");
return "Hello";
}, executorService);
// future01.runAfterBothAsync(future02,()->{
// System.out.println("任务3开始");
// },executorService);
// future01.thenAcceptBothAsync(future02, (f1,f2)->{
// System.out.println("任务3开始,之前的结果" + f1 + "-->" + f2);
// },executorService);
CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {
return f1 + ":" + f2 + "->haha";
}, executorService);
6、两任务组合-一个完成
- public CompletionStage<Void> runAfterEitherAsync (CompletionStage<?> other, Runnable action, Executor executor);
- public CompletionStage<Void> runAfterEitherAsync (CompletionStage<?> other, Runnable action);
- public CompletionStage<Void> runAfterEither(CompletionStage<?> other, Runnable action);
- public CompletionStage<Void> acceptEitherAsync (CompletionStage<? extends T> other, Consumer<? super T> action, Executor executor);
- public CompletionStage<Void> acceptEitherAsync (CompletionStage<? extends T> other, Consumer<? super T> action);
- public CompletionStage<Void> acceptEither (CompletionStage<? extends T> other, Consumer<? super T> action);
- public <U> CompletionStage<U> applyToEitherAsync (CompletionStage<? extends T> other, Function<? super T, U> fn, Executor executor);
- public <U> CompletionStage<U> applyToEitherAsync (CompletionStage<? extends T> other, Function<? super T, U> fn);
- public <U> CompletionStage<U> applyToEither (CompletionStage<? extends T> other, Function<? super T, U> fn);
7、多任务组合
- public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
- public static CompletableFuture<Object> anyOf(CompletableFuture<?>...
cfs)
allof:等待所有任务完成
anyof:只要有一个任务完成
本文深入探讨Java中线程的多种初始化方式,包括继承Thread、实现Runnable和Callable接口,以及利用线程池和CompletableFuture进行高效异步编程。详细解析线程池的参数配置与运行流程,介绍CompletableFuture的异步编排方法,如whenComplete、handle、thenApply等,帮助读者掌握线程管理和异步任务编排的最佳实践。
906

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



