区别:
先来写个Demo吧:
public class ThreadTest {
// 当前系统池只有一两个,每个异步任务直接提交给线程池,让他自己去执行
public static ExecutorService service = Executors.newFixedThreadPool(10);
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main...start....");
/**
* 1. 继承 Thread
* Thread01 thread = new Thread01();
* thread.start();
* 2. 实现 Runnable 接口
* Runable01 runable01 = new Runable01();
* new Thread(runable01).start();
* 3. 实现 Callable接口 + FutureTask (可以拿到返回结果,可以处理异常)
* FutureTask futureTask = new FutureTask<>(new Callable01());
* new Thread(futureTask).start();
* // 阻塞等待整个线程执行完成,获取返回结果
* Integer integer = futureTask.get();
* 4. 线程池
* 给线程池直接提交任务.
* 我们以后在业务代码里面,以上三种启动线程的方式都不用。【将所有的多线程异步任务都交给线程池执行】
* 区别:
* 1、2不能得到返回值,3可以获取返回值
* 1、2、3都不能控制资源
* 4 可以控制资源,系统性能稳定
*/
service.execute(new Runable01());
}
public static class Thread01 extends Thread {
@Override
public void run() {
System.out.println("当前线程: " + Thread.currentThread().getId());
int i = 10/2;
System.out.println("运行结果:" + i);
}
}
public static class Runable01 implements Runnable {
@Override
public void run() {
System.out.println("当前线程: " + Thread.currentThread().getId());
int i = 10/2;
System.out.println("运行结果:" + i);
}
}
public static class Callable01 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("当前线程: " + Thread.currentThread().getId());
int i = 10/2;
System.out.println("运行结果:" + i);
return i;
}
}
}
前两种实现方法这里不做过多讲解。
实现 Callable 接口并重写 call 方法,创建线程。可以获取线程执行结果的返回值,并且可以抛出异常;
Runbable 和 Callable 的区别?
Future接口
FutureTask类
Callable的执行方式
// FutureTask
FutureTask<Integer> futureTask1 = new FutureTask<>(new MyThread2());
new Thread(futureTask1,"BB").start();
System.out.println(futureTask1.get());
当然也可以进行Lambda进行简化(Callable是函数式接口):
// Lambda表达式进行简化
FutureTask<Integer> futureTask2 = new FutureTask<>(()->{
return 1024;
});
线程池[ExecutorService]
原生:service.execute(new Runable01());
创建
为什么需要线程池?
线程池的分类
核心参数
线程池的工作过程?
第一步、编写创建线程池工具类
1、添加线程池属性配置类,并注入到容器中
package com.atguigu.gulimall.product.config;
@ConfigurationProperties(prefix = "gulimall.thread")
@Component
@Data
public class ThreadPoolConfigProperties {
private Integer coreSize;
private Integer maxSize;
private Integer keepAliveTime;
}
这里提示需要导入一个工具依赖,不导也可以:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
2、添加线程池属性的配置
在gulimall-product服务中加入以下配置:
# 配置线程池
gulimall:
thread:
core-size: 20
max-size: 200
keep-alive-time: 10
3、线程池配置,获取线程池的属性值这里直接调用与配置文件相对应的属性配置类
package com.atguigu.gulimall.product.config;
@Configuration
public class MyThreadConfig {
@Bean
public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties pool) {
return new ThreadPoolExecutor(pool.getCoreSize(),
pool.getMaxSize(),
pool.getKeepAliveTime(),
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(100000),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
}
}
使用的时候只需要通过:
@Autowired
ThreadPoolExecutor executor;
Future 接口
Future 接口(FutureTask实现类)定义了操作 异步任务执行一些方法,如获取异步任务的执行结果、取消任务的执行、判断任务是否被取消、判断任务执行是否完毕等。
缺点:
get()
阻塞:一旦调用 get() 方法求结果,如果计算没有完成容易导致程序阻塞。isDone()
轮询:轮训的方式会耗费无谓的CPU资源,而且也不见得能及时地得到计算结果。CompletableFuture 对 Future 的改进
get()方法在Future 计算完成之前会一直处在 阻塞状态 下,isDone()方法容易耗费CPU资源,对于真正的异步处理我们希望是可以通过传入回调函数,在Future结束时自动调用该回调函数,这样,我们就不用等待结果。
阻塞的方式和异步编排的设计理念相违背,而轮训的方式会耗费无谓的CPU资源。因此,JDK8设计出 CompleatbleFuture。
CompleatbleFuture 提供了一种观察者模式类似的机制,可以让任务执行完成后通知监听的一方。
public class CompletableFuture<T> implements Future<T>, CompletionStage<T>
业务场景:
查询商品详情页的逻辑比较复杂,有些数据还需要远程调用,必然需要话费更多的时间:
假如商品详情页的每个查询,需要如下标注的时间才能完成。那么,用户需要5.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() 作为它的线程池执行异步代码。如果指定线程池,则使用指定的线程池运行。以下所有的方法都类同。
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main...start....");
/**
* 方法完成之后的感知
*/
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程: " + Thread.currentThread().getId());
int i = 10 / 0;
System.out.println("运行结果:" + i);
return i;
}, executor).whenComplete((result,exception)->{
// 虽然能得到异常信息,但是没法修改返回数据
System.out.println("异步任务成功完成了...结果是:" + result+";异常是:"+exception);
}).exceptionally(throwable -> {
// 可以感知异常同时返回指定默认值
System.out.println(throwable);
return 10;
});
System.out.println(future2.get());
System.out.println("main...end....");
}
计算完成时回调方法
当CompletableFuture的计算结果完成,或者抛出异常的时候,可以执行特定的Action。主要是下面的方法:
//可以处理异常,无返回值
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 的区别:
方法不以 Async 结尾,意味着 Action 使用相同的线程执行,而 Async 可能会使用其他线程执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main...start....");
/*
CompletableFuture future1 = CompletableFuture.runAsync(() -> {
System.out.println("当前线程: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
}, executor);*/
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程: " + Thread.currentThread().getId());
int i = 10 / 0;
System.out.println("运行结果:" + i);
return i;
}, executor).whenComplete((result,exception)->{
// 虽然能得到异常信息,但是没法修改返回数据
System.out.println("异步任务成功完成了...结果是:" + result+";异常是:"+exception);
}).exceptionally(throwable -> {
// 可以感知异常同时返回指定默认值
return 10;
});
System.out.println(future2.get());
System.out.println("main...end....");
}
handle 方法
handle 是执行任务完成时对结果的处理。 handle 方法和 thenApply 方法处理方式基本一样。不同的是:
public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn,Execut
/**
* 方法执行完成后的处理
*/
CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, executor).handle((res,thr)->{
if (res != null) {
return res *2;
}
if (thr != null) {
return 0;
}
return 0;
});
System.out.println(future3.get());
线程串行化
带有 Async 默认是异步执行的。同之前
// thenRun
public CompletableFuture<Void> thenRun(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action,
Executor executor);
// thenAccept
public CompletableFuture<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 <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn);
public <U> CompletionStage<U> thenApplyAsync
(Function<? super T,? extends U> fn);
public <U> CompletionStage<U> thenApplyAsync
(Function<? super T,? extends U> fn,
Executor executor);
测试代码:
/**
* 线程串行化
* 1)、thrnRun :不能获取到上一步的执行结果,并无返回值
* 2)、thenAccept : 能接收上一步结果,但是无返回值
* 3)、thenApply :能接收上一步结果,并有返回值
*/
CompletableFuture<Void> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程1: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, executor).thenRunAsync(() -> {
System.out.println("任务2启动了...");
}, executor);
CompletableFuture<Void> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程2: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, executor).thenAcceptAsync(res->{
System.out.println("任务2启动了..." + res);
},executor);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程2: " + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, executor).thenApplyAsync(res -> {
System.out.println("任务2启动了..." + res);
return "Hello" + res;
}, executor);
System.out.println("返回值:"+future.get());
两任务组合-都要完成
thenCombine 会把两个 CompletionStage 的任务都执行完成后,把两个任务的结果一块交给 thenCombine 来处理。
runAfterBoth
组合两个 future,不需要获取 future 的结果,只需两个 future 处理完任务后,处理该任务。
两个CompletionStage,都完成了计算才会执行下一步的操作(Runnable)
public CompletionStage<Void> runAfterBoth(CompletionStage<?> other,Runnable action);
public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action);
public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor
thenAcceptBoth
组合两个 future,获取两个 future 任务的返回结果,然后处理任务,没有返回值
当两个CompletionStage都执行完成后,把结果一块交给thenAcceptBoth来进行消耗
public <U> CompletionStage<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
public <U> CompletionStage<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action, Executor executor);
thenCombine
组合两个 future,获取两个 future 的返回结果,并返回当前任务的返回值
thenCombine 会把 两个 CompletionStage 的任务都执行完成后,把两个任务的结果一块交给 thenCombine 来处理。
public <U,V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn,Executor executor);
测试代码:
/**
* 两个异步任务都完成
*/
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务1线程: " + Thread.currentThread().getId());
int i = 10 / 4;
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.runAfterBothAsync(future02, ()->{
System.out.println("任务3开始...");
},executor);
future01.thenAcceptBothAsync(future02, (f1,f2)->{
System.out.println("任务3开始,之前的结果:f1="+f1+";f2="+f2);
},executor);
CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {
return f1 + ":" +f2 +"->HaHa";
}, executor);
System.out.println("方法3的返回结果:" + future.get());
两任务组合-只要有一个任务完成就执行第三个
两个 CompletionStage 的返回类型要一致
runAfterEither 方法
两个任务有一个任务完成,不需要获取 future 的结果,处理任务,也没有返回值
两个CompletionStage,任何一个完成了都会执行下一步的操作(Runnable)
public CompletionStage<Void> runAfterEither(CompletionStage<?> other,Runnable action);
public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action);
public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor);
acceptEither 方法
两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值
两个CompletionStage,谁执行返回的结果快,我就用那个CompletionStage的结果进行下一步的消耗操作。
public CompletionStage<Void> acceptEither(CompletionStage<? extends T> other,Consumer<? super T> action);
public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action);
public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? supe
applyToEither 方法
两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值
两个CompletionStage,谁执行返回的结果快,我就用那个CompletionStage的结果进行下一步的转化操作。
public <U> CompletionStage<U> applyToEither(CompletionStage<? extends T> other,Function<? super T, U> fn);
public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn);
public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? sup
测试代码:
/**
* 两个异步任务只要有一个完成,我们就执行任务3
* runAfterEither: 不感知结果,自己也没有返回值
* acceptEither : 感知结果,自己没有返回值
*/
CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务1线程: " + Thread.currentThread().getId());
int i = 10 / 4;
System.out.println("任务1结束");
return i;
}, executor);
CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务2线程: " + Thread.currentThread().getId());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务2结束");
return "Hello";
}, executor);
// CompletableFuture future3 = future01.runAfterEitherAsync(future02, () -> {
// System.out.println("任务3开始...");
// }, executor);
// CompletableFuture future4 = future01.acceptEitherAsync(future02, (res) -> {
// System.out.println("任务3开始..." + res);
// }, executor);
CompletableFuture<String> future = future01.applyToEitherAsync(future02, res -> {
System.out.println("任务3开始..." + res);
return res.toString() + "-->haha";
}, executor);
System.out.println("main...end...." + future.get());
}
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs);
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs);
allOf 测试代码:
CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品图片信息");
return "hllo.jpg";
}, executor);
CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品的属性");
return "星空白+256G";
}, executor);
CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("查询商品的介绍");
return "苹果";
}, executor);
CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
allOf.get(); // 等待所有结果完成
System.out.println("main...end...." );
anyOf 测试代码:
CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("查询商品图片信息");
return "hllo.jpg";
}, executor);
CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("查询商品的属性");
return "星空白+256G";
}, executor);
CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("查询商品的介绍");
return "苹果";
}, executor);
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
anyOf.get();