1.Async
用于不需要返回值,通过注解来异步执行耗时操作;如果没有配置线程池,使用默认的线程池;
2.ExecutorService
1>对于不需要返回值的,直接调用execute方法即可;
public static void main(String[] args) {
ExecutorService executorService= Executors.newSingleThreadExecutor();
executorService.execute(()->{
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("ddd");
});
}
2>需要等待返回值的
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService= Executors.newSingleThreadExecutor();
Future<Double> test = executorService.submit(() -> {
System.out.println(Thread.currentThread() + " start,time->" + System.currentTimeMillis());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
if (false) {
throw new RuntimeException("test");
} else {
System.out.println(Thread.currentThread() + " exit,time->" + System.currentTimeMillis());
}
return 1.2;
});
System.out.println(test.get());
}
另外,还提供invokeAll,提供批量的提交调用;
3.CompletableFuture
可以进行更复杂的多个异步操作,并且协调之间的先后顺序;
1>runAsync和supplyAcync创建子任务
runAsync提供无返回结果的任务;
supplyAcync提供有返回结果的任务;
注意,某些特别耗时的异步任务可能很浪费时间,因此强烈建议针对每个业务使用自己的线程池;如果不设置的话,使用系统默认线程池;
public static void main(String[] args) throws ExecutionException, InterruptedException {
try {
runAsyncDemo();
supplyAsyncDemo();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void runAsyncDemo() throws Exception {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1000);
System.out.println("run end...");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
//等待异步任务执行完成,限时等待2秒
future.get(2, TimeUnit.SECONDS);
}
//创建一个无消耗值(无输入值)、有返回值的异步子任务
public static void supplyAsyncDemo() throws Exception {
CompletableFuture<Long> future = CompletableFuture.supplyAsync(() -> {
long start = System.currentTimeMillis();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("run end...");
return System.currentTimeMillis() - start;
});
//等待异步任务执行完成,限时等待2秒
long time = future.get(2, TimeUnit.SECONDS);
System.out.println("异步执行耗时(秒):" + time / 1000);
}
这两个方法,也可以传入一个线程池,通过线程池来执行;如果没有线程池,使用默认的ForkJoinPool.commonPool()来执行,默认的线程数是cpu的核数;
执行完成之后的回调,可以使用几种方式:
//设置子任务完成时的回调钩子
public CompletableFuture<T> whenComplete(
BiConsumer<? super T, ? super Throwable> action)
//设置子任务完成时的回调钩子,可能不在同一线程执行
public CompletableFuture<T> whenCompleteAsync(
BiConsumer<? super T, ? super Throwable> action)
//设置子任务完成时的回调钩子,提交给线程池executor执行
public CompletableFuture<T> whenCompleteAsync(
BiConsumer<? super T, ? super Throwable> action, Executor executor)
//设置异常处理的回调钩子
public CompletableFuture<T> exceptionally(
Function<Throwable, ? extends T> fn)
public class CompletableFutureDemo1 {
public static void whenCompleteDemo() throws Exception {
//创建异步任务
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
//模拟执行一秒
sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+":抛出异常");
throw new RuntimeException(Thread.currentThread().getName()+":发生异常");
});
//设置异步任务执行完成后的回调钩子
future.whenComplete(new BiConsumer<Void, Throwable>() {
@Override
public void accept(Void unused, Throwable throwable) {
System.out.println(Thread.currentThread().getName()+":执行完成!");
}
});
//设置异步任务发生异常后的回调钩子
future.exceptionally(new Function<Throwable, Void>() {
@Override
public Void apply(Throwable throwable) {
System.out.println(Thread.currentThread().getName()+":执行失败!" + throwable.getMessage());
return null;
}
});
}
public static void main(String[] args) throws Exception {
whenCompleteDemo();
sleep(2000);
}
}
执行结果
ForkJoinPool.commonPool-worker-9:抛出异常
ForkJoinPool.commonPool-worker-9:执行失败!java.lang.RuntimeException: ForkJoinPool.commonPool-worker-9:发生异常
ForkJoinPool.commonPool-worker-9:执行完成!
发生异常时,先执行eceptionally中的,再执行whenComplete里面的方法;
在调用get方法时,如果异步任务中抛出异常,那么get方法也会异常;
也可以使用handler来处理
//创建异步任务
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
//模拟执行一秒
sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+":抛出异常");
throw new RuntimeException(Thread.currentThread().getName()+":发生异常");
});
future.handle(new BiFunction<Void, Throwable, Object>() {
@Override
public Object apply(Void unused, Throwable throwable) {
if (throwable == null) {
System.out.println(Thread.currentThread().getName()+":没有发生异常!");
} else {
System.out.println(Thread.currentThread().getName()+":sorry,发生了异常!"+throwable.getMessage());
}
return null;
}
});
异步任务之间,可以串行执行
//后一个任务与前一个任务在同一个线程中执行
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
//后一个任务与前一个任务不在同一个线程中执行
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
//后一个任务在指定的executor线程池中执行
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
public static void whenCompleteDemo() throws Exception {
//创建异步任务
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
//模拟执行一秒
sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
future.thenApply(new Function<Void, Object>() {
@Override
public Object apply(Void unused) {
System.out.println("sss");
return null;
}
});
}
注意,thenApply如果前面一个任务抛出异常,这个任务是不会执行的;前面一个任务的返回结果会传递到第二个任务里面,作为参数;另外还有thenRun方法,只要前面一个执行完成,后面一个就开始执行;