在业务开发中,有很多异步场景,为了节约时间或或者提高系统的吞吐量,要做一些异步任务,在Java中要实现异步通常都是Thread,开启一个线程Thread,开启线程有四种方式。
1)、继承Thread
2)、实现Runnable接口
3)、实现Callable接口+FutureTask(可以拿到返回结果,可以处理异常)
4)、线程池
方式1和方式2:主进程无法获取线程的运算结果。不适合我们当前的场景。
方式3:主进程可以获取线程的运算结果,但是不利于控制服务器中的线程资源。
线程测试:
/**
* @Description 线程测试
*/
public class ThreadTest {
public static void main(String[] args) throws Exception {
System.out.println("main...start...");
//1)、继承Thread
Thread01 thread01 = new Thread01();
//启动线程
thread01.start();
//2)、实现Runnable接口
Runable01 runable01 = new Runable01();
new Thread(runable01).start();
// 3)、实现Callable接口+FutureTask(可以拿到返回结果,可以处理异常)
FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
new Thread(futureTask).start();
// 阻塞等待整个线程执行完成,获取返回结果
Integer integer = futureTask.get();
System.out.println("返回值:" + integer.intValue());
// 4)、线程池[ExecutorService] 给线程池直接提交任务。
//ExecutorService service = Executors.newFixedThreadPool(3);
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
5,
200,
10L,
TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>(10000),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
// 定时任务的线程池
ExecutorService service = Executors.newScheduledThreadPool(2);
service.execute(new Runable01());
System.out.println("main...end...");
}
}
class Thread01 extends Thread {
@Override
public void run() {
System.out.println("Thread当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("Thread运行结果:" + i);
}
}
class Runable01 implements Runnable {
@Override
public void run() {
System.out.println("Runnable当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("Runnable运行结果:" + i);
}
}
class Callable01 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("Callable当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("Callable运行结果:" + i);
return i;
}
}
执行结果:
main...start...
main...end...
Thread当前线程:13
Thread运行结果:5
可以看到开启线程,进入了异步,主程序已经结束,线程才打印。
JUC线程池
业务场景:
查询商品详情页的逻辑比较复杂,有些数据还需要远程调用,必然需要花费更多的时间。
假如商品详情页的每个查询,用户需要6.5s 后才能看到商品详情页的内容,这是显然不能接受的。
如果多个线程同时完成这个 6 步操作,也许只需要 1.5s 即可响应完成。
CompletableFuture
提供了四个静态方法来创建一个异步操作。
public static CompletableFuture<Void> runAsync(Runnable runnable);
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor);
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) ;
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor);
没有指定Executor的方法会使用 ForkJoinPool.commonPool() 作为它的线程池执行异步代码。如果指定线程池,则使用指定的线程池运行。
当CompletableFuture
的计算结果完成,或者抛出异常的时候,可以执行特定的Action
。主要是下面的方法:
//返回相同的结果或例外,这一阶段的新completionstage,这个阶段完成时,执行特定动作的结果(或 null如果没有)和异常(或 null如果没有)这个阶段。
public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action);
//返回相同的结果或例外,这一阶段的新completionstage,这个阶段完成时,执行特定动作执行给定的操作这一阶段的默认的异步执行设施,其结果(或 null如果没有)和异常(或 null如果没有)这个阶段作为参数。
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action);
//返回相同的结果或例外,这一阶段的新completionstage,这个阶段完成时,执行使用所提供的遗嘱执行人,给出的行动与结果(或 null如果没有)和异常(或 null如果没有)这个阶段作为参数。
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor);
//返回一个新的completablefuture已经完成与给定值。
public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn);
测试:
/**
* whenCompleteAsync 依赖于上一层的CompletableFuture 的返回值作为这个阶段的参数进行某些操作,返回的仍然是上一层的CompletableFuture
* whenCompleteAsync和whenComplete的区别:
* whenCompleteAsync为异步,可能并不是执行上一层代码的线程
* whenComplete为执行上一层代码的线程执行这个阶段的逻辑
*
*/
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
int i = 10 / 2;
return i;
}).whenCompleteAsync((t, u) -> {
int m = t*2; //可以利用回调值做一些操作计算
System.out.println("上一层依赖的CompletableFuture返回的结果是:" + t);
System.out.println("上一层依赖的CompletableFuture返回的异常结果是:" + u);
});
Integer result = future.get();
System.out.println("CompletableFuture.whenCompleteAsync运行后结果是:"+result);
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:");
return i;
}, executor).handle(
(t, u) -> {
if (t != null)//有返回值
return t * 2;
if (u != null)//发生异常
return 0;
return 0;
}
);
Integer integer = future.get();
System.out.println("main...end... 结果:" + integer);
}
thenApply
方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前任务的返回值。thenAccept
方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果thenRun
方法:只要上面的任务执行完成,就开始执行thenRun,只是处理完任务后,执行 thenRun的后续操作每一个方法都对应了三种操作。带有Async
默认是异步执行的。这里所谓的异步指的是不在当前线程内执行。带有参数Executor executor
的则用指定的线程池方案,不指定的话则用默认的ForkJoinPool.commonPool()
。
// T : 上一个任务返回结果的类型 U:当前任务的返回值的类型
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 CompletionStage<Void> thenAccept(Consumer<? super T> action);
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor);
public CompletionStage<Void> thenRun(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action,Executor executor);
thenApplyAsync
CompletableFuture<Integer> thenApply = CompletableFuture.supplyAsync(() -> {
return 100;
}).thenApplyAsync(t -> {
return t * 2;
});
Integer result = thenApply.get();
System.out.println(result);//200
thenAcceptAsync
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
return 100;
}).thenAcceptAsync(t -> {
t = t*2;
System.out.println("t========>"+t);//t========>200
});
System.out.println(future.get());//null
两个任务必须都完成,触发该任务。
1、thenCombine
:组合两个future
,获取两个future
任务的返回结果,并返回当前任务的返回值
2、thenAcceptBoth
:组合两个future
,获取两个future
任务的返回结果,然后处理任务,没有返回值。
3、runAfterBoth
:组合两个future
,不需要获取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);
组合两个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);
组合两个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);
组合两个future,不需要获取future的结果,只需两个future处理完任务后,处理该任务
thenAcceptBothAsync
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务1:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("任务1结束");
return i;
}, executor);
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务2:" + Thread.currentThread().getId());
System.out.println("任务2结束");
return "Hello";
}, executor);
future01.thenAcceptBothAsync(future02,
(f1, f2) -> {
System.out.println("任务3开始......之前的结果:" + f1 + "/" + f2);
},
executor);
CompletableFuture<String> future = future01.thenCombineAsync(future02,
(f1, f2) -> {
return f1 + ":" + f2;
}
, executor);
System.out.println("main...end..." + future.get());
当两个任务中,任意一个future任务完成的时候,执行任务
applyToEither
:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值.acceptEither
:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值.runAfterEither
:两个任务有一个执行完成,不需要future的结果,处理任务,也没有返回值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));
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) );
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));
1、allOf
:等待所有任务完成
2、anyOf
:只要有一个任务完成
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs);
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs);