一、首先分为简单实现跟线程池方式实现:
简单实现:
1、有返回值
继承Thread类、实现Runnable接口
2、无返回值
实现Callable接口
使用线程池实现:
1、有返回值
2、无返回值
二、实现异步的方式
1、异步编程之CompletableFuture
2、Spring的@Async异步
一、简单实现
1)继承Thread,重写run方法:
class MyThread extends Thread {
@Override
public void run() {
System.out.println("继承Thread,重写run方法创建线程");
}
}
public class Main {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
//直接使用匿名内部类实现
public class Main {
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("使用匿名内部类创建 Thread 子类对象");
}
};
thread.start();
}
}
//lambda表达式
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("使用lambda表示创建线程");
});
thread.start();
}
}
2)实现Runnable接口,重写run方法:实现Runnable接口,需要嵌套在Thread中创建实例,然后调用start方法实现
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("实现Runnable接口,重写run方法");
}
}
public class Main {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
}
}
//使用匿名内部类实现
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("使用匿名内部类,实例Runnable接口作为构造参数");
}
});
thread.start();
}
}
3)实现Callable接口,因为有返回值,所以需要嵌套在FutureTask类中中创建实例,然后再将FutureTask嵌套在Thread类中创建实例,然后调用start()方法,就可以FutureTask.get()方法中得到返回值。
class MyCallableTest implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("创建线程:" + Thread.currentThread().getName());
return 2;
}
}
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> task = new FutureTask<>(new MyCallableTest());
Thread thread = new Thread(task);
thread.start();
System.out.println("创建线程的返回结果为:" + task.get());
}
}
二、使用线程池实现
线程池实现,需要先创建线程池:
@Configuration
public class ThreadPoolConfig {
/** Set the ThreadPoolExecutor's core pool size. */
private int CORE_POOL_SIZE = 5;
/** Set the ThreadPoolExecutor's maximum pool size. */
private int MAXIMUM_POOL_SIZE = 15;
/** Set the capacity for the ThreadPoolExecutor's BlockingQueue. */
private int QUEUE_CAPACITY = 1000;
@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(CORE_POOL_SIZE);
// 设置最大线程数
executor.setMaxPoolSize(MAXIMUM_POOL_SIZE);
// 设置队列容量
executor.setQueueCapacity(QUEUE_CAPACITY);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(1000);
// 设置默认线程名称
executor.setThreadNamePrefix("Test-Thread-");
// 设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
主要靠的是两个方法:submit() 和 execute()方法
execute()只能执行实现Runnable接口类型的任务;execute()没有返回值
submit()不仅可以执实现Runnable类型接口的任务,也可以执行实现Callable接口类型的任务,submit()有在添加Callable类型任务的时候有返回值。
1)无返回值
public static void main(String[] args) throws ExecutionException, InterruptedException {
/** Set the ThreadPoolExecutor's core pool size. */
int CORE_POOL_SIZE = 5;
/** Set the ThreadPoolExecutor's maximum pool size. */
int MAXIMUM_POOL_SIZE = 15;
/** Set the capacity for the ThreadPoolExecutor's BlockingQueue. */
int QUEUE_CAPACITY = 1000;
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(CORE_POOL_SIZE);
// 设置最大线程数
executor.setMaxPoolSize(MAXIMUM_POOL_SIZE);
// 设置队列容量
executor.setQueueCapacity(QUEUE_CAPACITY);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(1000);
// 设置默认线程名称
executor.setThreadNamePrefix("Test-Thread-");
// 设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
// List<FutureTask<String>> list = new ArrayList();
for(int i = 0;i<10;i++){
executor.execute(new ThreadTest1()); //继承Thread
executor.submit(new ThreadTest1()); //继承Thread
executor.execute(new ThreadTest2());//实现Runnable
executor.submit(new ThreadTest2());//实现Runnable
}
executor.shutdown();
}
2)有返回值
public static void main(String[] args) throws ExecutionException, InterruptedException {
/** Set the ThreadPoolExecutor's core pool size. */
int CORE_POOL_SIZE = 5;
/** Set the ThreadPoolExecutor's maximum pool size. */
int MAXIMUM_POOL_SIZE = 15;
/** Set the capacity for the ThreadPoolExecutor's BlockingQueue. */
int QUEUE_CAPACITY = 1000;
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(CORE_POOL_SIZE);
// 设置最大线程数
executor.setMaxPoolSize(MAXIMUM_POOL_SIZE);
// 设置队列容量
executor.setQueueCapacity(QUEUE_CAPACITY);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(1000);
// 设置默认线程名称
executor.setThreadNamePrefix("Test-Thread-");
// 设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
for(int i = 0;i<10;i++){
Future submit = executor.submit(new ThreadTest3());
System.out.println(submit.get());
}
executor.shutdown();
}
三、异步编程之CompletableFuture
CompletableFuture对Future进行了扩展,可以通过设置回调的方式处理计算结果,同时也支持组合操作,支持进一步的编排,同时一定程度解决了回调地狱的问题。
1)开启异步编程
runAsync:无入参、无返回值
supplyAsync :无入参,可以获取返回值
/**
* 定义线程池
*/
public static ExecutorService executor = Executors.newFixedThreadPool(5);
//supplyAsync 使用默认线程池
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务...");
return "开启异步任务,我是返回值";
});
//supplyAsync 使用创建线程池
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务...");
return "开启异步任务,我是返回值";
},executor);
//runAsync 使用默认线程池
CompletableFuture<String> future = CompletableFuture.runAsync(() -> {
System.out.println("开启异步任务...");
});
//runAsync 使用创建线程池
CompletableFuture<String> future = CompletableFuture.runAsync(() -> {
System.out.println("开启异步任务...");
},executor);
2)计算完成回调
当我们想第一个异步任务执行完成后,还需要做其他的事情。我们的CompletableFuture
提供了计算完成时回调方法,whenComplete
、whenCompleteAsync
、exceptionally
等接口。
whenComplete
可以处理正常和异常的计算结果,exceptionally
: 处理异常情况
whenComplete
和whenCompleteAsync
的区别是whenComplete 是执行当前任务的线程继续执行whenComplete的任务。whenCompleteAsync 是把whenCompleteAsync的任务继续提交给线程池来进行执行。
//whenCompleteAsync
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务...");
int i = 10 / 2;
return i;
}, service).whenCompleteAsync((res, exc) -> {
System.out.println("异步任务完成了,执行结果是:" + res + " 异常是:" + exc);
});
System.out.println("获取异步任务返回值:" + future.get());
//whenCompleteAsync
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务...");
int i = 10 / 2;
if (i == 5) {
throw new RuntimeException("远程服务调用失败");
}
return i;
}, service).whenCompleteAsync((res, exc) -> {
System.out.println("异步任务完成了,执行结果是:" + res + " 异常是:" + exc);
});
注意不管是使用supplyAsync创建还是使用runAsync创建异步,我们都需要在future.get()方法才能在主程序中抛出异常,但是future.get()会阻塞主线程。并且会比如第二个线程抛出异常,也会影响后面线程返回值得获取。
例如这样:
exceptionally 可以捕获并消除异常,但是也必须在最后获取future.get()方式才有效。
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务...");
int i = 10 / 2;
if (i == 5) {
throw new RuntimeException("远程服务调用失败");
}
return i;
}, service).whenCompleteAsync((res, exc) -> {
System.out.println("异步任务完成了,执行结果是:" + res + " 异常是:" + exc);
}).exceptionally(throwable -> {
System.out.println("进入了异常处理,捕获了" + throwable.getMessage() + "异常");
return 5;
});
System.out.println("获取异步任务返回值:" + future.get());
这样处理了异常之后,如果选择不在抛出,就不会阻塞主线程展示如下:
也可以重新return ,修改异步线程得返回值..如果有异常才会重置,没异常就不会重置。
3)handle最终处理
实际上handle等于whenComplete
+ exceptionally 这两个操作,前面说whenComplete
可以感知异常,获取返回值,exceptionally可以处理异常,并修改返回值。
handle实际上可以既捕获异常,并修改返回值。
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务...");
int i = 10 / 2;
if (i == 5) {
throw new RuntimeException("远程服务调用失败");
}
return i;
}, service).handleAsync((res, thr) -> {
System.out.println("进入handleAsync方法");
if (res != null) {
return res * 2;
}
if (thr != null) {
System.out.println("捕获到异常" + thr);
return 0;
}
return 0;
}, service);
System.out.println("获取异步任务返回值:" + future.get());
4)线程串行化
串行化的意思就是,两个线程互相影响,第一个线程完成时才开始第二个线程
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 CompletableFuture<Void> thenAccept(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor)
public CompletableFuture<Void> thenRun(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action,Executor executor)
- thenRun方法:不能获取上一步的执行结果,并且最后无返回值。
- thenAccept方法:接收上一步的执行结果,但是最后无返回值。
- thenApply 方法:接收上一步的执行结果,并且最后有返回值。
thenRun:
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务...");
int i = 10 / 2;
return i;
}, service).thenRun(() -> {
System.out.println("任务2启动了...");
});
System.out.println("获取异步任务返回值:" + future.get());
thenAccept:
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务...");
int i = 10 / 2;
return i;
}, service).thenAcceptAsync((res) -> {
System.out.println("任务2启动了... 上一步的结果是:" + res);
}, service);
System.out.println("获取异步任务返回值:" + future.get());
thenApply:
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务...");
int i = 10 / 2;
return i;
}, service).thenApplyAsync((res) -> {
System.out.println("任务2启动了... 上一步的结果是:" + res);
return res * 2;
}, service);
System.out.println("获取异步任务最终返回值:" + future.get());
5)两任务组合-两个任务都完成才继续执行
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);
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)
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)}
- runAfterBoth 两个都完成才执行,不接受前两个的返回值,最后也没有返回值。
- thenAcceptBoth 两个都完成才执行,接收前两个的返回值,但是最后没有没返回值
- thenCombine 两个都完成才执行,接收前两个的返回值,最后有返回值
runAfterBoth
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务1...");
int i = 10 / 2;
return i;
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务2...");
return "hello";
});
future1.runAfterBoth(future2, () -> {
System.out.println("任务3 启动了....");
});
thenAcceptBoth
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务1...");
int i = 10 / 2;
return i;
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务2...");
return "hello";
});
future1.thenAcceptBoth(future2, (res1, res2) -> {
System.out.println("任务3 启动了.... 任务1的返回值:" + res1 + " 任务2的返回值:" + res2);
});
thenCombine:
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务1...");
int i = 10 / 2;
return i;
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务2...");
return "hello";
});
CompletableFuture<String> stringCompletableFuture = future1.thenCombine(future2, (res1, res2) -> {
System.out.println("任务3 启动了.... 任务1的返回值:" + res1 + " 任务2的返回值:" + res2);
return res1 + "-->" + res2;
});
6)两任务组合- 只要有一个任务完成就继续执行
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)
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 <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)
当两个任务中,任意一个future任务完成的时候,执行任务。
- runAfterEither 两个任务有一个执行完成就继续,不获取任一结果,最后也没有返回值。
- acceptEither 两个任务有一个执行完成,获取先执行完的返回值,最后没有返回值。
- applyToEither 两个任务有一个任务执行完成,获取先执行完的返回值,最后有返回值。
runAfterEither
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务1...");
int i = 10 / 2;
return i;
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("开启异步任务2...");
return "hello";
});
future1.runAfterEither(future2, () -> {
System.out.println("任务3 启动了....");
});
acceptEither:
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务1...");
int i = 10 / 2;
return i;
});
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("开启异步任务2...");
return 10;
});
future1.acceptEither(future2, (res) -> {
System.out.println("任务3 启动了...., 任务结果是:" + res);
});
applyToEither:
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务1...");
int i = 10 / 2;
return i;
});
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("开启异步任务2...");
return 10;
});
CompletableFuture<String> stringCompletableFuture = future1.applyToEither(future2, (res) -> {
System.out.println("任务3 启动了...., 上个任务结果是:" + res);
return "我是任务三的返回值, 上个任务的执行结果是:" + res;
});
System.out.println(stringCompletableFuture.get());
7)多任务组合
当多个任务影响下一个线程时,需要用到一下api:
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)
- allOf:返回的
CompletableFuture
是多个任务都执行完成后才会执行,只要有一个任务执行异常,则返回的CompletableFuture
执行get
方法时会抛出异常,如果都是正常执行,则get
返回null
- anyOf: 返回的
CompletableFuture
是多个任务只要其中一个执行完成就会执行,其get
返回的是已经执行完成的任务的执行结果,如果该任务执行异常,则抛出异常。
allOf
CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread()+" start job1,time->"+System.currentTimeMillis());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread()+" exit job1,time->"+System.currentTimeMillis());
return 1.2;
});
CompletableFuture<Double> cf2 = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread()+" start job2,time->"+System.currentTimeMillis());
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread()+" exit job2,time->"+System.currentTimeMillis());
return 3.2;
});
CompletableFuture<Double> cf3 = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread()+" start job3,time->"+System.currentTimeMillis());
try {
Thread.sleep(1300);
} catch (InterruptedException e) {
}
// throw new RuntimeException("test");
System.out.println(Thread.currentThread()+" exit job3,time->"+System.currentTimeMillis());
return 2.2;
});
//allof等待所有任务执行完成才执行cf4,如果有一个任务异常终止,则cf4.get时会抛出异常,都是正常执行,cf4.get返回null
//anyOf是只有一个任务执行完成,无论是正常执行或者执行异常,都会执行cf4,cf4.get的结果就是已执行完成的任务的执行结果
CompletableFuture cf4=CompletableFuture.allOf(cf,cf2,cf3).whenComplete((a,b)->{
if(b!=null){
System.out.println("error stack trace->");
b.printStackTrace();
}else{
//拼接返回值
Double join1 = cf.join();
Double join2 = cf2.join();
Double join3 = cf3.join();
System.out.println("结果 join1、join2、join3"+join1+join2+join3);
}
});
System.out.println("main thread start cf4.get(),time->"+System.currentTimeMillis());
//等待子任务执行完成
System.out.println("cf4 run result->"+cf4.get());
System.out.println("main thread exit,time->"+System.currentTimeMillis());
anyOf:
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品图片...");
return "图片地址";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品属性...");
return "黑色 256G";
});
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品品牌...");
return "苹果手机";
});
CompletableFuture<Object> objectCompletableFuture = CompletableFuture.anyOf(future1, future2, future3);
System.out.println("第一个执行成功的数据:" + objectCompletableFuture.get());
8) get,getNow和join方法区别
Future.get()
和 Future.join()
是 java.util.concurrent.Future
接口提供的两个方法,用于获取异步任务的结果。它们的主要区别如下:
抛出异常
Future.get()
方法声明了throws Exception
,需要手动处理可能抛出的异常Future.join()
方法没有声明抛出异常,如果任务内部抛出异常,会包装为CompletionException(unchecked异常)
并抛出。Future.getNow()
方法不会抛出异常,而是将异常包装在ExecutionException
中,并作为结果返回。阻塞行为
Future.get()
方法是一个阻塞方法,即调用该方法后会一直等待任务完成并返回结果,如果任务未完成,调用线程会被阻塞
。Future.join()
方法也是一个阻塞方法,但它是使用ForkJoinPool
线程池中的工作线程执行任务,如果调用线程是ForkJoinPool
线程池中的工作线程,则不会出现阻塞,而是直接执行任务。Future.getNow()
方法是一个非阻塞方法
,如果任务已经完成,会立即返回结果,如果任务未完成,则返回传入的默认值默认值
:Future.getNow(默认值)
方法需要传入一个默认值作为参数,如果任务未完成,则返回该默认值。如果不传入默认值,则会返回null
总的来说,Future.get()
方法在获取异步任务结果时更具灵活性,因为它可以抛出异常且可以手动处理,但它会阻塞调用线程。而 Future.join()
方法更适用于使用 ForkJoinPool
线程池执行任务的情况,它更方便使用且不会阻塞 ForkJoinPool
线程池中的工作线程
四、Spring的@Async异步
在@Async注解之前,使用多线程需要使用JDK的原生方法,非常麻烦,当有了@Async之后就比较简单了。
1)首先,使用 @EnableAsync 启用异步注解,在启动类上加上该注解:
@SpringBootApplication
@EnableAsync
public class StartApplication {
public static void main(String[] args) {
SpringApplication.run(StartApplication.class, args);
}
}
2)自定义线程池:见上
3)在异步处理的方法上添加注解 @Async ,当对 execute 方法 调用时,通过自定义的线程池 defaultThreadPoolExecutor 异步化执行 execute 方法
@Service
public class AsyncServiceImpl implements AsyncService {
@Async("defaultThreadPoolExecutor")
public Boolean execute(Integer num) {
System.out.println("线程:" + Thread.currentThread().getName() + " , 任务:" + num);
return true;
}
}
用 @Async 注解标记的方法,称为异步方法。在spring boot应用中使用 @Async 很简单:
1、调用异步方法类上或者启动类加上注解 @EnableAsync
2、在需要被异步调用的方法外加上 @Async
3、所使用的 @Async 注解方法的类对象应该是Spring容器管理的bean对象;
注意:
1、在类中调用 本类中被@Async 修饰的方法就不会被异步执行, 所以 @Async 方法尽量放在单独的类中,而不要挤在 冗余的代码中。
2、@Async
方法默认不会继承父方法的事务。如果需要事务支持,请确保异步方法和调用该方法的方法都被@Transactional
注解标记。
3、异步方法中抛出的异常不能直接捕获,因为调用者将无法获取到异常。建议使用Future
或CompletableFuture
来捕获异步方法的异常并进行处理。
4、异步方法默认情况下是没有返回值的,如果需要获取异步方法的执行结果,依然要使用Future
或CompletableFuture
,可以将其设置为返回类型。
未完还需总结:
1、Spring ApplicationEvent事件实现异步
2、消息队列
3、ThreadUtil异步工具类
4、Guava异步