继承Thread
public class ThreadTest{
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 void main(String[] args){
Thread01 thread01 = new Thread01();
thread01.start(); // 启动线程
}
}
实现Runnable接口
public class ThreadTest{
public static class Runnable01 implements Runnable {
@Override
public void run() {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果: " + i);
}
}
public static void main(String[] args){
Runnable01 runnable01 = new Runnable01();
new Thread(runnable01).start();
}
}
实现Callable接口+ FutureTask ( 可以拿到返回结果,可以处理异常)
public class ThreadTest{
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;
}
}
public static void main(String[] args){
// 使用Future执行Callable
FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
new Thread(futureTask).start(); // FutureTask 是Runnable的实现类
// get() 堵塞等待整个线程执行完成,获取返回结果
Integer integer = futureTask.get();
System.out.println("integer = " + integer);
}
}
线程池
public class ThreadTest{
// 最原始的方式
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,
200,
10,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(10000),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
// 包装之后简化线程池的创建(jdk8 的特性)
public static ExecutorService executor = Executors.newFixedThreadPool(10);
}
总结:
方式1和方式2:主进程无法获取线程的运算结果。不适合当前场景
方式3:主进程可以获取线程的运算结果,但是不利于控制服务器中的线程资源。可以导致服务器资源耗尽。
方式4:通过如下两种方式初始化线程池
Executors.newFiexedThreadPool(3);
//或者
new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit unit,workQueue, threadFactory, handler);
通过线程池性能稳定,也可以获取执行结果,并捕获异常。但是,在业务复杂情况下,一个异步调用可能会依赖于另一个异步调用的执行结果。
七大参数
工作顺序
面试题: 一个线程池core 7,max 20 ,queue 50 100并发进来怎么分配的
7个会立即执行,50个会进入队列,再开13个进行执行。剩下的30个就使用拒绝策略(默认是丢弃)。如果不想丢弃我们可以在创建线程池的时候执行拒绝策略 CallerRunsPolicy
public class ThreadTest{
Executors.newCachedThreadPool(); // core 是0,所有都可以回收,来一个任务就创建一个线程
Executors.newFixedThreadPool(10); // 固定线程数量,core = max = 10 就是都不可回收
Executors.newScheduledThreadPool(10); // core=10,定时任务的线程池,从队列里面获取任务可以设置延迟时间。
Executors.newSingleThreadExecutor(); // 单线程的线程池,堵塞的任务都放入队列中,挨个执行
}
业务场景:查询商品详情页的逻辑比较复杂,有些数据还需要远程调用,必然需要花费更多的时间。
异步编排的好处:假如商品详情页的每个查询,需要如下标注的时间才能完成。那么,用户需要6.5s后才能看到商品详情页的内容。很显然是不能接受的。如果有多个线程同时完成这6步操作,也许只需要1.5s 即可完成响应。
CompletableFuture提供了四个静态方法来创建一个异步操作。
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
return asyncSupplyStage(asyncPool, supplier);
}
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
Executor executor) {
return asyncSupplyStage(screenExecutor(executor), supplier);
}
public static CompletableFuture<Void> runAsync(Runnable runnable) {
return asyncRunStage(asyncPool, runnable);
}
public static CompletableFuture<Void> runAsync(Runnable runnable,
Executor executor) {
return asyncRunStage(screenExecutor(executor), runnable);
}
1、runXxx都是没有返回结果的, supplyXx都是可以获取返回结果的
2、可以传入自定义的线程池,否则就用默认的线程池;
public CompletableFuture<T> whenComplete(
BiConsumer<? super T, ? super Throwable> action) {
return uniWhenCompleteStage(null, action);
}
public CompletableFuture<T> whenCompleteAsync(
BiConsumer<? super T, ? super Throwable> action) {
return uniWhenCompleteStage(asyncPool, action);
}
public CompletableFuture<T> whenCompleteAsync(
BiConsumer<? super T, ? super Throwable> action, Executor executor) {
return uniWhenCompleteStage(screenExecutor(executor), action);
}
public CompletableFuture<T> exceptionally(
Function<Throwable, ? extends T> fn) {
return uniExceptionallyStage(fn);
}
public <U> CompletableFuture<U> handle(
BiFunction<? super T, Throwable, ? extends U> fn) {
return uniHandleStage(null, fn);
}
public <U> CompletableFuture<U> handleAsync(
BiFunction<? super T, Throwable, ? extends U> fn) {
return uniHandleStage(asyncPool, fn);
}
public <U> CompletableFuture<U> handleAsync(
BiFunction<? super T, Throwable, ? extends U> fn, Executor executor) {
return uniHandleStage(screenExecutor(executor), fn);
}
public <U> CompletableFuture<U> thenApplyAsync(
Function<? super T,? extends U> fn, Executor executor) {
return uniApplyStage(screenExecutor(executor), fn);
}
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,
Executor executor) {
return uniAcceptStage(screenExecutor(executor), action);
}
public CompletableFuture<Void> thenRunAsync(Runnable action,
Executor executor) {
return uniRunStage(screenExecutor(executor), action);
}
thenApply方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前任务的返回值。
thenAccept方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果。
thenRun方法:只要上面的任务执行完成,就开始执行thenRun,只是处理完任务后,执行thenRun的后续操作
* 1) thenRunAsync: 不能获取到上一步的结果,无返回值
* 2) thenAcceptAsync: 能获取当上一步的结果,无返回值
* 3) thenApplyAsync : 能获取到上一步的结果,有返回值
总结:
public <U,V> CompletableFuture<V> thenCombineAsync(
CompletionStage<? extends U> other,
BiFunction<? super T,? super U,? extends V> fn, Executor executor) {
return biApplyStage(screenExecutor(executor), other, fn);
}
public <U> CompletableFuture<Void> thenAcceptBothAsync(
CompletionStage<? extends U> other,
BiConsumer<? super T, ? super U> action, Executor executor) {
return biAcceptStage(screenExecutor(executor), other, action);
}
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
Runnable action,
Executor executor) {
return biRunStage(screenExecutor(executor), other, action);
}
两个任务必须都完成,触发该任务。
thenCombine: 组合两个future,获取两个future的返回结果,并返回当前任务的返回值
thenAcceptBoth:组合两个future,获取两个future任务的返回结果,然后处理任务,没有返回值。
runAfterBoth: 组合两个future,不需要获取future 的结果,只需两个future处理完任务后,处理该任务。
* runAfterBothAsync 拿不到两个future 的结果,无返回值
* thenAcceptBothAsync 能拿到两个future 的结果,无返回值
* thenCombineAsync 能拿到两个future 的结果,有返回值
public <U> CompletableFuture<U> applyToEitherAsync(
CompletionStage<? extends T> other, Function<? super T, U> fn,
Executor executor) {
return orApplyStage(screenExecutor(executor), other, fn);
}
public CompletableFuture<Void> acceptEitherAsync(
CompletionStage<? extends T> other, Consumer<? super T> action,
Executor executor) {
return orAcceptStage(screenExecutor(executor), other, action);
}
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
Runnable action,
Executor executor) {
return orRunStage(screenExecutor(executor), other, action);
}
当两个任务中,任意一个future任务完成的时候,执行任务。
applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值。
acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值
runAfterEither:两个任务有一一个执行完成,不需要获取future的结果,处理任务,也没有返回值。
两个任务只要有一个完成,我们就执行任务3
* runAfterEitherAsync 不能感知结果,没有返回值
* acceptEitherAsync 能感知结果,没有返回值(注册的future 返回值类型必须一致)
* applyToEitherAsync 能感知结果,有返回值(注册的future 返回值类型必须一致)
CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
allOf.get(); // 等待所有的结果完成
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc, futureNone);
System.out.println("最快完成的任务->" + anyOf.get()); // 这个就是第一个完成的future 的返回值,只要有一个完成就不堵塞
allOf:等待所有任务完成
anyOf:只要有一个任务完成
线程池和异步编排能提供我们服务器的性能和吞吐量。线程池是性能,异步编排是吞吐量。