CompletableFuture 线程编排
关键字记忆
when 任务完成时回调
both 两任务组合,都要完成
either 两任务组合,任一完成即可
run 无参无返回, apply 有参有返回, accept 有参无返回
async 异步
参考资料地址:
多线程之异步编排实例详解
创建线程的几种方式
import lombok.SneakyThrows;
import org.junit.Test;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
/**
* 创建线程的几种方式
*
* @author lyn
* @date 2024/04/02 14:20
**/
public class CreateThreadMethodTest {
@Test
public void test1() {
Thread01 thread01 = new Thread01();
thread01.start();
}
@Test
public void test2() {
Runnable01 runnable01 = new Runnable01();
Thread thread = new Thread(runnable01);
thread.start();
}
@SneakyThrows
@Test
public void test3() {
FutureTask<String> futureTask = new FutureTask<>(new Callable01());
new Thread(futureTask).start();
System.out.println(futureTask.get());
System.out.println("阻塞等待线程执行完成,获取返回结果");
}
@SneakyThrows
@Test
public void test4() {
ExecutorService executorService = Executors.newFixedThreadPool(5);
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println("4 线程池的方式");
}
});
}
public class Thread01 extends Thread {
@Override
public void run() {
System.out.println("1 继承Thread类的方式");
}
}
public class Runnable01 implements Runnable {
@Override
public void run() {
System.out.println("2 实现Runnable接口的方式");
}
}
public class Callable01 implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("3 实现callable 接口的方式");
Thread.sleep(1000);
return "res";
}
}
}
线程编排
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* 线程编排
* 参考资料链接: https://blog.csdn.net/weixin_53922163/article/details/128177316
* @author lyn
* @date 2024/04/08 10:42
**/
@Slf4j
public class CompletableFutureTest {
ExecutorService threadPool = Executors.newFixedThreadPool(5);
@SneakyThrows
@Test
public void test() {
}
/**
* 7 多任务组合
*/
@SneakyThrows
@Test
public void test7() {
CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品图片信息");
return "hello.jpg";
}, threadPool);
CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品属性");
return "白色+1TB";
}, threadPool);
CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品介绍");
return "Apple";
}, threadPool);
// 有一个任务执行完成 返回结果
System.out.println(CompletableFuture.anyOf(futureImg, futureAttr, futureDesc).get());
// 等待所有任务执行完成 返回结果
CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
System.out.println("任务结果: " + futureImg.get() + " " + futureAttr.get() + " " + futureDesc.get());
}
/**
* 6 两任务组合 - 一个完成
*/
@SneakyThrows
@Test
public void test6() {
CompletableFuture<String> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务1启动");
return "任务1";
}, threadPool);
CompletableFuture<String> supplyAsync2 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务2启动");
return "任务2";
}, threadPool);
supplyAsync1.runAfterEitherAsync(supplyAsync2, () -> {
System.out.println("任务三启动");
});
supplyAsync1.acceptEither(supplyAsync2, res -> {
System.out.println("任务三启动," + res);
});
System.out.println(supplyAsync1.applyToEitherAsync(supplyAsync2, (res) -> {
System.out.println("任务三启动," + res);
return res + "任务3";
}).get());
}
/**
* 5 两任务组合 - 都要完成
*/
@SneakyThrows
@Test
public void test5() {
CompletableFuture<String> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务1启动");
return "任务1";
}, threadPool);
CompletableFuture<String> supplyAsync2 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务2启动");
return "任务2";
}, threadPool);
//使用 runAfterBothAsync (无法获取之前任务执行的结果):
supplyAsync1.runAfterBothAsync(supplyAsync2, () -> {
System.out.println("任务3启动");
}).get();
//使用 thenAcceptBothAsync(可获取之前任务执行的结果,但不能返回)
supplyAsync1.thenAcceptBothAsync(supplyAsync2, (p1, p2) -> {
System.out.println("任务3启动," + p1 + "," + p2);
}, threadPool).get();
//使用 thenCombineAsync(可获取之前任务执行的结果,可修改并返回结果):
String combineRes = supplyAsync1.thenCombineAsync(supplyAsync2, (p1, p2) -> {
System.out.println("任务3启动," + p1 + "," + p2);
return p1 + p2;
}, threadPool).get();
System.out.println(combineRes);
}
/**
* 4 线程串行化方法
*/
@SneakyThrows
@Test
public void test4() {
//1 thenApply 方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前任务的返回值
CompletableFuture<Object> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread());
String i = "welcome";
System.out.println("运行结果:" + i);
return i;
}, threadPool).thenApplyAsync(res -> {
System.out.println("当前线程" + Thread.currentThread());
String i = res + " beijing";
System.out.println("运行结果:" + i);
return i;
}, threadPool);
System.out.println(supplyAsync1.get());
//2 thenAccept 方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果。
CompletableFuture<Void> supplyAsync2 = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread());
String i = "welcome";
System.out.println("运行结果:" + i);
return i;
}, threadPool).thenAcceptAsync(res -> {
System.out.println("当前线程" + Thread.currentThread());
String i = res + " beijing";
System.out.println("运行结果:" + i);
}, threadPool);
System.out.println(supplyAsync2.get());
//3 thenRun 方法:只要上面的任务执行完成,就开始执行 thenRun,只是处理完任务后,执行 thenRun 的后续操作
CompletableFuture<Void> supplyAsync3 = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread());
String i = "welcome";
System.out.println("运行结果:" + i);
return i;
}, threadPool).thenRunAsync(() -> {
System.out.println("当前线程" + Thread.currentThread());
String i = " beijing";
System.out.println("运行结果:" + i);
}, threadPool);
System.out.println(supplyAsync3.get());
}
/**
* 3 方法执行完成后的处理
*/
@SneakyThrows
@Test
public void test3() {
CompletableFuture<Integer> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
return 1;
}, threadPool).handle((res, ex) -> res + 1).whenComplete((res, ex) -> {
System.out.println("异步任务完成,结果为: " + res + ",异常为:" + ex);
});
}
/**
* 2 计算完成时回调方法
*/
@SneakyThrows
@Test
public void test2() {
//1 whenComplete 是使用当前任务的线程继续执行任务。
CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread());
int i = 10 / 0;
System.out.println("运行结果:" + i);
return 1;
}, threadPool).whenComplete((res, ex) -> {
System.out.println("计算完成后调用回调方法");
System.out.println("当前线程" + Thread.currentThread().getName());
System.out.println("异步任务完成,结果为: " + res + ",异常为:" + ex);
});
System.out.println("Main...Start...." + Thread.currentThread());
// supplyAsync 可获取返回值
//2 whenCompleteAsync是将任务继续提交给线程池来进行执行
CompletableFuture<Integer> result = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程" + Thread.currentThread());
int i = 10 / 0;
System.out.println("运行结果:" + i);
return i;
}, threadPool).whenCompleteAsync((res, exception) -> {
// 当上面的任务执行完成,能得到结果和异常信息,但无法修改返回值
System.out.println("异步任务完成,结果为:" + res + ",异常为:" + exception);
}).exceptionally(throwable -> {
// 可以感知异常,同时返回默认值
return 101;
});
Integer integer = result.get();
System.out.println("Main...End...." + integer);
}
/**
* 1 创建异步对象
*/
@SneakyThrows
@Test
public void test1() {
//使用默认的线程池,无返回值
CompletableFuture<Void> runAsync1 = CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName() + "执行任务");
});
//使用自定义的线程池,无返回值
CompletableFuture<Void> runAsync2 = CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName() + "执行任务");
}, threadPool);
//使用默认的线程池,有返回值
CompletableFuture<String> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "执行任务");
return "1";
});
System.out.println("supplyAsync1 结果:" + supplyAsync1.get(10, TimeUnit.MILLISECONDS));
//使用自定义的线程池,有返回值
CompletableFuture<String> supplyAsync2 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "执行任务");
return "2";
}, threadPool);
System.out.println("supplyAsync2 结果:" + supplyAsync2.get(10, TimeUnit.MILLISECONDS));
}
}