本质是一个运行的程序,是系统资源分配的基本单位,每一个进程都有一个独立的内存地址空间:(包括代码空间,数据空间),每一个进程内存空间,数据空间都是私有的,不能被其他的进程访问:进程与进程之间相互隔离的。
线程是为了让CPU执行更高效提出的。
1)上下文切换
问题1: 现在的机器可以运行远大于CPU核心数的线程运行,操作资源是如何分配的?
CPU采用时间分片的模式,将CPU的时间片段轮流分配给多个线程执行;分配给每个线程的时间大概是几十毫秒ms,线程在CPU时间片执行,如果当前线程没有执行结束,CPU时间分片已经结束,此线程就会被挂起,下一个时间分片将会分给下一个线程,上一个线程等待唤醒。
问题2: 线程没有执行完毕,线程别挂起,等待下次被唤醒,继续完成任务!系统是怎么知道线程之前运行到哪里?从哪里开始执行呢??
CPU包含
CPU在执行任务时候,都必须依赖寄存器,程序计数器;这些东西就是CPU切换的开销,称之为上下文切换
2)线程的调度
问题1:操作系统如何共享CPU时间分片,如何分配CPU执行权限?线程何时分到时间分片?线程分配多长时间?如何给重要的线程多分配一点时间,次要的少分配点时间呢?
(1)抢占式调度
并发线程下,所有线程会抢占时间分片,获取执行权限。有些线程执行时间长,造成线程堵塞等待,等待CPU资源。
JVM线程调度:抢占式调度模式
(2)协同式调用
一个线程执行完成后主动通知系统切换到另一个线程执行;(同步堵塞)
致命缺点:一个线程堵塞,则会导致整个进程堵塞,一个线程异常,则会导致整个进程崩溃
3)并行和并发
继承Thread类,实现多线程
public static void main(String[] args) {
System.out.println("thread.........start...........");
/* 1. 测试Thread实现的多线程 */
// 创建多线程对象
ThreadA threadA = new ThreadA();
// 开启线程
threadA.start();
System.out.println("thread.........end.............");
}
public static class ThreadA extends Thread {
/**
* run方法是线程执行主体,多线程任务在run方法中执行。
*/
@Override
public void run() {
log.info("继承Thread实现方式.....");
// 业务代码执行
int i = 100 / 3;
log.info("业务代码执行的结果为:{},线程的名称:{},线程的ID:{}", i, this.getName(), this.getId());
}
}
总结:多线程线程的执行,是在主线程执行完毕后再执行的。(体现了异步的效果)
实现Runnable接口,实现多线程
(1)普通构建方式
public static void main(String[] args) {
System.out.println("thread.........start...........");
/* 测试实现Runnable接口,实现多线程 */
// 创建多线程对象
Thread02 thread02 = new Thread02();
// 构建多线程对象
Thread thread = new Thread(thread02);
// 开启线程
thread.start();
System.out.println("thread.........end.............");
}
public static class Thread02 implements Runnable {
/**
* run方法是线程执行主体,多线程任务在run方法中执行。
*/
@Override
public void run() {
log.info("实现Runnable接口的实现方式.....");
// 业务代码执行
int i = 100 / 3;
log.info("业务代码执行的结果为:{}", i);
}
}
(2)匿名内部类实现方式
public static void main(String[] args) {
System.out.println("thread.........start...........");
/* 测试实现Runnable接口,实现多线程 */
// 创建多线程对象
Runnable runnable = new Runnable() {
@Override
public void run() {
log.info("实现Runnable接口的实现方式.....");
// 业务代码执行
int i = 100 / 3;
log.info("业务代码执行的结果为:{}", i);
}
};
// 构建多线程对象
Thread thread = new Thread(runnable);
// 开启线程
thread.start();
System.out.println("thread.........end.............");
}
(3)lambda表达式方式(推荐使用,但需要了解下lambda表达式实现原理)
public static void main(String[] args) {
System.out.println("thread.........start...........");
/* 测试实现Runnable接口,实现多线程 */
// lambda创建多线程对象,直接传入Thread构造参数中,并开启线程
new Thread(() -> {
log.info("实现Runnable接口的实现方式.....");
// 业务代码执行
int i = 100 / 3;
log.info("业务代码执行的结果为:{}", i);
}).start();
System.out.println("thread.........end.............");
}
lambda表达式的特点:
1. @FunctionalInterface:表示可以使用lambda表达式编程,此注解相当于一个标识
2. 接口如果只有一个方法(必须满足),即使没有上面的注解,也可以使用lambda表达式;程序会在后台自动识别。
lambda表达式写作形式:方法括号(有参写,无参不写) -> {业务执行方法体}
Callable + FutureTask实现多线程
jdk1.5后: 添加Callable接口,实现多线程,相较于Thread和Runnable接口而言,Callable有返回值。
@FunctionalInterface
:表示支持lambda表达式
public interface Callable
:
疑问: 由于多线程执行必须和Thread有关系,Callable和Thread有什么关系呢?
因为Runnable
的实现类FutureTask
即创建了Runnable
接口的构造函数,也创建了Callable
接口的构造函数 。
同时Thread
类需要的是一个对Runnable
接口的实现类,而RunnableFuture
是继承于Runnable
的,FutureTask
是RunnableFuture
实现类,所以通过FutureTask
构造的多线程对象可以直接传入Thread
使用。。
(1)普通实现方式
public static void main(String[] args) {
System.out.println("thread.........start...........");
// 创建多线程对象
Thread03 thread03 = new Thread03();
// 创建FutureTask对象,将thread03对象传递到构造函数中
FutureTask<Integer> task = new FutureTask<>(thread03);
// 创建多线程对象
Thread thread = new Thread(task);
// 开启线程执行
thread.start();
try {
// 等待子线程执行结束后,获取返回结果,该代码为同步阻塞,必须等待异步线程执行结束,且返回结果后,才能继续往下执行。
Integer integer = task.get();
System.out.println("子程序运行结果为:" + integer);
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
System.out.println("thread.........end.............");
}
public static class Thread03 implements Callable<Integer> {
/**
* 业务执行主体
* @return 返回值
* @throws Exception 异常捕获
*/
@Override
public Integer call() throws Exception {
log.info("实现Callable接口的实现方式.....");
// 业务代码执行
int i = 100 / 3;
log.info("业务代码执行的结果为:{}", i);
return i;
}
}
(2)匿名内部类实现方式
public static void main(String[] args) {
System.out.println("thread.........start...........");
// 创建多线程对象
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
log.info("实现Callable接口的实现方式.....");
// 业务代码执行
int i = 100 / 3;
log.info("业务代码执行的结果为:{}", i);
return i;
}
};
// 创建FutureTask对象,将Callable接口对象传递到构造函数中
FutureTask<Integer> task = new FutureTask<>(callable);
// 创建多线程对象
Thread thread = new Thread(task);
// 开启线程执行
thread.start();
try {
// 等待子线程执行结束后,获取返回结果,该代码为同步阻塞,必须等待异步线程执行结束,且返回结果后,才能继续往下执行。
Integer integer = task.get();
System.out.println("子程序运行结果为:" + integer);
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
System.out.println("thread.........end.............");
}
(3)lambda表达式实现方式
public static void main(String[] args) {
System.out.println("thread.........start...........");
// 创建FutureTask对象,通过lambda表达式实现Callable接口
FutureTask<Integer> task = new FutureTask<>(() -> {
log.info("实现Callable接口的实现方式.....");
// 业务代码执行
int i = 100 / 3;
log.info("业务代码执行的结果为:{}", i);
return i;
});
// 创建多线程对象
Thread thread = new Thread(task);
// 开启线程执行
thread.start();
try {
// 等待子线程执行结束后,获取返回结果,该代码为同步阻塞,必须等待异步线程执行结束,且返回结果后,才能继续往下执行。
Integer integer = task.get();
System.out.println("子程序运行结果为:" + integer);
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
System.out.println("thread.........end.............");
}
问题1: 什么是线程池?
通俗易懂的来讲,就是事先准备好一些资源,有人要用(业务系统需要使用线程),就来线程池里拿(从线程池里获取线程),用完后还不能销毁,必须还给我(线程池的可复用性)。
问题2: 为什么要使用线程池?(池化技术)
从问题3可以得出,线程的创建和销毁时很浪费时间和系统资源的,所以需要通过线程池来提高效率。
问题3: 执行一个Java任务,可以直接new Thread来运行任务,线程从创建到消耗经历了哪些过程?
Executors
(不推荐,最大线程数不可控)new ThreadPoolExecutor();
(推荐,稳定可控)基本构建方式
// 1.创建线程池对象;创建单个线程的线程池对象
ExecutorService executorService1 = Executors.newSingleThreadExecutor();
// 线程执行
try {
for (int i = 0; i < 10; i++) {
executorService1.execute(() -> {
log.info("通过Executors创建线程池的方式实现多线程.....");
// 业务代码执行
int num = 100 / 3;
log.info("业务代码执行的结果为:{}", num);
});
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// 线程池用完了,关闭线程池
executorService1.shutdown();
}
线程池的分类
// 1.创建线程池对象;创建单个线程的线程池对象
ExecutorService executorService1 = Executors.newSingleThreadExecutor();
// 2.创建固定数量的线程池(指定核心线程数数量),核心线程数为2
ExecutorService executorService2 = Executors.newFixedThreadPool(2);
// 3.创建一个按照计划执行的线程池
ScheduledExecutorService executorService3 = Executors.newScheduledThreadPool(2);
// 4.创建一个自动增长的线程池
ExecutorService executorService4 = Executors.newCachedThreadPool();
警告: 任何时候都不建议使用Executor
创建线程池方式,因为这样创建的线程池会无限制的增长线程池大小,从而导致内存被占满,线程量大导致性能严重下降,甚至OOM!
解决方案: 使用ThreadPoolExecutor
类,来可控的创建线程池。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize: 线程池的核心线程数;初始化线程池时,会创建核心线程,进入等待状态,核心线程不会被销毁,提供线程的复用。
maximumPoolSize: 最大线程数;核心线程用完了,必须新建线程执行任务,但是新建线程数不会超过最大线程数。
keepAliveTime: 线程的存活时间,除了核心线程以外(maximumPoolSize - corePoolSize)的线程存活时间;当线程处于空闲状态,他可以活多久。
unit: 存活时间单位
workQueue: 任务阻塞队列,任务可能会很多,线程只有几个,因此可以将多余的任务放进队列进行缓冲,队列采用FIFO的,等待线程空闲,再从队列中取出任务执行。
threadFactory: 线程工厂,默认使用defaultThreadFactory
用来创建线程,一般使用默认即可。
RejectedExecutionHandler: 线程池拒绝策略
四种拒绝策略
合理配置线程相关的参数:核心线程数、最大线程数。
设置线程池的线程数量:根据业务类型进行设置(CPU密集型,IO密集型)
最大线程数设置公式: (任务执行时间 / 任务CPU时间) * N(CPU核心数)
在Java并发编程中,使用线程池,还必须使用任务队列,让任务在队列中进行缓冲:可以线程执行防洪泄流的效果,提升线程池处理任务能力;
通常在线程池中,使用的都是阻塞队列;
问题: 如何选择一个合适的队列呢?
基于Java的一些队列特性:
ArrayBlockingQueue
:基于数组实现的有界阻塞队列(有界的队列)LinkedBlockingQueue
:基于链表实现的有界阻塞队列PriorityBlockingQueue
:支持按照优先级排序的无界阻塞队列DelayQueue
:基于优先级实现的无界阻塞队列SynchronousQueue
:只存储一个元素,如果该元素未被消费,就不能向里面存储元素。LinkedTransferQueue
:基于链表实现的无界阻塞队列LinkedBlockingDeque
:基于链表实现实现的双向的无界阻塞队列。推荐: 建议使用有界的队列。
原因: 有界队列能增加系统的稳定性,根据需求设置大一些(可控设置);如果设置为无界队列,遇到不可控的因素,可能会导致队列中的任务越来越多,出现OOM,撑爆整个系统
异步调用实现一个不需要被等等的方法的返回值;让调用者继续执行(异步执行);在java中,简单的讲就是开启另一个线程完成程序计算,使得调用者继续执行,不需要等等计算的结果,但是调用者仍然需要获取线程的计算结果(不需要同步阻塞等待)。
Future是一个异步计算结果返回接口,目的获取返回值结果。但是future在获取返回值结果的时候,方法必须同步阻塞等待返回值结果。
get()
:获取结果(等待,阻塞)isDone
:判断任务是否已经完成(轮询等待)Future对于获取结果来说是非常不方便的,只能通过同步阻塞的方式获取结果,或者是轮训得方式获取结果;同步阻塞与异步思想相违背,轮训又很占用CPU资源,不能及时得到结果,所以JDK8中设计出了CompletableFuture
CompletableFuture 是对 Future 的改进
CompletableFuture
的作用:帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以通过回调函数的方式处理计算结果。
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
从CompletableFuture
的实现类可以看出,CompletableFuture
具有Future
的特性,还具备了CompletionStage
的特性:串行执行,并行执行,聚合(AND聚合,OR聚合)
由于查询CSDN作者详情页的业务逻辑复杂,数据的获取需要远程调用,这导致运行起来十分耗时,例如下面
如果CSDN作者详情页的查询都需要以上标注时间才能完成。那用户需要3.13s后才能看到作者详情页的内容,很明显是不能接受的。如果有多个线程同时完成这4步操作,也许只需要1.8s即可完成响应。
CompletableFuture 提供了四个静态方法来创建一个异步操作。
// runAsync方法不支持返回值。
public static CompletableFuture<Void> runAsync(Runnable runnable);
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor);
// supplyAsync可以支持返回值。
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
没有指定Executor
的方法会使用 ForkJoinPool.commonPool()
作为它的线程池执行异步代码。如果指定线程池,则使用指定的线程池运行。以下所有的方法都类同。
带有 Async 默认是异步执行的。
接口介绍:
// thenRun:类似流水线,前面的任务完成后,就开始执行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);
// thenApply:接收上一个任务的处理结果,并返回当前任务的返回值。(有传参,有返回值)
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);
// thenCompose:接收上一个任务的处理结果,并且能够执行流水线式的第二个CompletionStage。(有传参,有返回值)
public <U> CompletionStage<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn);
public <U> CompletionStage<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn);
public <U> CompletionStage<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn, Executor executor);
测试代码:
/**
* 线程串行化
* 1. thrnRun :不能获取到上一步的执行结果,并无返回值
* 2. thenAccept : 能接收上一步结果,但是无返回值
* 3. thenApply :能接收上一步结果,并有返回值
* 4. thenCompose :接连处理第二个CompletionStage,能接收上一步结果,并有返回值。
*/
/* thenRun */
CompletableFuture<Void> thenRunFuture = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start...........");
int i = 10 / 2;
log.info("线程名称:{},线程的执行结果为:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end.............");
return i;
}).thenRun(() -> {
log.info("thenRun子线程开始运行.............");
});
// 调用执行
thenRunFuture.get();
/* thenAccept */
CompletableFuture<Void> thenAcceptFuture = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start...........");
int i = 10 / 2;
log.info("线程名称:{},线程的执行结果为:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end.............");
return i;
}).thenAccept((t) -> {
log.info("thenAccept子线程开始运行,参数是:{}", t);
long res = t * 5L;
log.info("计算结果是:{}", res);
});
// 调用执行
thenAcceptFuture.get();
/* thenApply */
CompletableFuture<Long> thenApplyFuture = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start...........");
int i = 10 / 2;
log.info("线程名称:{},线程的执行结果为:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end.............");
return i;
}).thenApply((t) -> {
log.info("thenAccept子线程开始运行,参数是:{}", t);
long res = t * 5L;
log.info("计算结果是:{}", res);
return t * 5L;
});
// 调用执行
Long aLong = thenApplyFuture.get();
log.info("最终计算结果是:{}", aLong);
/* thenCompose */
// 第一个 CompletionStage
CompletableFuture<Long> thenComposeFuture = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start...........");
int i = 10 / 2;
log.info("线程名称:{},线程的执行结果为:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end.............");
return i;
}).thenCompose(new Function<Integer, CompletionStage<Long>>() {
@Override
public CompletionStage<Long> apply(Integer t) {
// 第二个 CompletionStage
CompletableFuture<Long> future = CompletableFuture.supplyAsync(() -> {
log.info("thenCompose子线程开始执行,参数是:{}", t);
long res = t * 5L;
log.info("计算结果:{}", res);
return res;
});
return future;
}
});
// 调用执行
Long aLong = thenComposeFuture.get();
log.info("最终计算结果是:{}", aLong);
特点: 两个任务组合起来,并且都要完成。
接口介绍:
// runAfterBoth:将两个CompletionStage任务组合起来,无需运行结果,两个任务运行完后,运行该任务。(无传参,无返回值)
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 executor);
// thenAcceptBoth:将两个任务的结果交给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:将两个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);
测试代码:
/**
* 线程聚合
* 1. runAfterBoth :不能接收两个任务的执行结果,并无返回值
* 2. thenAcceptBoth : 能接收两个任务的执行结果,但是无返回值
* 3. thenCombine :能接收两个任务的执行结果,并有返回值
*/
/* runAfterBoth */
// 第一个 CompletionStage
CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start...........");
int i = 10 / 2;
log.info("线程名称:{},线程的执行结果为:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end.............");
return i;
});
// 第二个 CompletionStage
CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start...........");
int i = 10 / 3;
log.info("线程名称:{},线程的执行结果为:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end.............");
return i;
});
// 利用runAfterBoth方法对f1,f2进行合并操作
CompletableFuture<Void> f = f1.runAfterBoth(f2, () -> {
log.info("有个任务在执行:runAfterBoth方法正在运行.......");
});
// 调用执行
f.get();
/* runAfterBoth */
// 第一个 CompletionStage
CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start...........");
int i = 10 / 2;
log.info("线程名称:{},线程的执行结果为:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end.............");
return i;
});
// 第二个 CompletionStage
CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start...........");
int i = 10 / 3;
log.info("线程名称:{},线程的执行结果为:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end.............");
return i;
});
// 利用thenAcceptBoth方法对f1,f2进行合并操作,并输出f1,f2的执行结果
CompletableFuture<Void> f = f1.thenAcceptBoth(f2, (t, u) -> {
log.info("第一个 CompletableFuture 执行结果:{}", t);
log.info("第二个 CompletableFuture 执行结果:{}", u);
});
// 调用执行
f.get();
/* thenCombine */
// 第一个 CompletionStage
CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start...........");
int i = 10 / 2;
log.info("线程名称:{},线程的执行结果为:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end.............");
return i;
});
// 第二个 CompletionStage
CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start...........");
int i = 10 / 3;
log.info("线程名称:{},线程的执行结果为:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end.............");
return i;
});
// 利用thenCombine方法对f1,f2进行合并操作,获取f1,f2的执行结果,并返回f1和f2的运算结果
CompletableFuture<Integer> f = f1.thenCombine(f2, (t, u) -> {
log.info("第一个 CompletableFuture 执行结果:{}", t);
log.info("第二个 CompletableFuture 执行结果:{}", u);
return t+u;
});
// 调用执行
Integer integer = f.get();
log.info("最终计算结果是:{}", integer);
特点: 两个任务组合起来,只要有一个任务完成就执行第三个。
接收介绍:
// runAfterEither:两个任务有一个任务完成,无需获取任务执行结果,处理runAfterEither任务。(无传参,无返回值)
// 两个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:两个任务有一个任务完成,获取任务执行结果,处理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<? super T> action, Executor executor);
// applyToEither:两个任务有一个任务完成,获取任务执行结果,处理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<? super T, U> fn, Executor executor);
测试代码:
/**
* 线程聚合
* 1. runAfterEither :不能接收上个任务的执行结果,并无返回值
* 2. acceptEither : 能接收上个任务的执行结果,但是无返回值
* 3. applyToEither :能接收上个任务的执行结果,并有返回值
*/
/* runAfterEither */
// 第一个 CompletionStage
CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start...........");
int i = 10 / 2;
log.info("线程名称:{},线程的执行结果为:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end.............");
return i;
});
// 第二个 CompletionStage
CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start...........");
int i = 10 / 3;
log.info("线程名称:{},线程的执行结果为:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end.............");
return i;
});
// 利用runAfterEither,在f1,f2执行完成后执行runAfterEither任务
CompletableFuture<Void> f = f1.runAfterEither(f2, () -> {
log.info("有个任务在执行:runAfterEither方法正在运行.......");
});
// 调用执行
f.get();
/* acceptEither */
// 第一个 CompletionStage
CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start...........");
int i = 10 / 2;
log.info("线程名称:{},线程的执行结果为:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end.............");
return i;
});
// 第二个 CompletionStage
CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start...........");
int i = 10 / 3;
log.info("线程名称:{},线程的执行结果为:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end.............");
return i;
});
// 利用acceptEither获取上一个任务的执行结果,并执行acceptEither的任务
CompletableFuture<Void> f = f1.acceptEither(f2, (t) -> {
log.info("acceptEither子线程正在运行,传递的参数是:{}", t);
});
// 调用执行
f.get();
/* applyToEither */
// 第一个 CompletionStage
CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start...........");
int i = 10 / 2;
log.info("线程名称:{},线程的执行结果为:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end.............");
return i;
});
// 第二个 CompletionStage
CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start...........");
int i = 10 / 3;
log.info("线程名称:{},线程的执行结果为:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end.............");
return i;
});
// 利用applyToEither获取上一个任务的执行结果,并执行applyToEither的任务,返回结果值
CompletableFuture<Integer> f = f1.applyToEither(f2, (t) -> {
log.info("acceptEither子线程正在运行,传递的参数是:{}", t);
return t * 5;
});
// 调用执行
Integer integer = f.get();
log.info("最终计算结果是:{}", integer);
// allOf : 等待所有任务完成
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs);
// anyOf :只有一个任务完成
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs);
allOf测试代码:
// 第一个 CompletionStage
CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
log.info("查看CSDN作者头像");
return 1;
});
// 第二个 CompletionStage
CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
log.info("查看作者分类列表");
return 2;
});
// 第三个 CompletionStage
CompletableFuture<Integer> f3 = CompletableFuture.supplyAsync(() -> {
log.info("查看作者文章列表");
return 3;
});
// 利用allOf,按照CompletableFuture定义顺序,统一执行
CompletableFuture<Void> allOf = CompletableFuture.allOf(f2, f1, f3);
// 调用执行
allOf.get();
anyOf测试代码:
// 第一个 CompletionStage
CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return 1;
});
// 第二个 CompletionStage
CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return 2;
});
// 第三个 CompletionStage
CompletableFuture<Integer> f3 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return 3;
});
// 通过anyOf调用,获取率先完成的任务结果。
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(f1, f2, f3);
// 调用执行
System.out.println(anyOf.get());
// exceptionally:处理异常情祝,同时返回默认值。
public CompletionStage<T> exceptionally(Function<Throwable, ? extends T> fn);
// whenComplete:可以处理正常和异常的计算结果,虽然能得到异常信息,但是没法修改返回的数据。
public CompletionStage<T> whenComplete(BiConsumer<? super T, ? super Throwable> action);
public CompletionStage<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action);
public CompletionStage<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action,Executor executor);
// handle:类似于try{}finally{},可对结果做最后的处理(可处理异常),可改变返回值。
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,Executor executor);
代码测试:
/* exceptionally */
CompletableFuture<Integer> f = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start............");
int i = 10 / 0;
log.info("线程名称:{},线程执行结果:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end............");
return i;
}).exceptionally((t)->{
log.info("业务执行失败:{}",t.getMessage());
return null;
});
/* whenComplete */
CompletableFuture<Integer> f = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start............");
int i = 10 / 0;
log.info("线程名称:{},线程执行结果:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end............");
return i;
}).whenComplete((t, u) -> {
log.info("上一步执行结果:{}",t);
// 判断
if(u!=null){
log.info("执行错误,有异常:{}",u.getMessage());
}
});
Integer integer = f.get();
log.info("最终执行结果:{}",integer);
/* handle */
CompletableFuture<Integer> f = CompletableFuture.supplyAsync(() -> {
log.info("子线程future线程start............");
int i = 10 / 2;
log.info("线程名称:{},线程执行结果:{}", Thread.currentThread().getName(), i);
log.info("子线程future线程end............");
return i;
}).handle((t, u) -> {
int res = -1;
if (u != null) {
log.info("执行错误:{}", u.getMessage());
} else {
res = t * 5;
}
return res;
});
Integer integer = f.get();
log.info("最终执行结果:{}",integer);