java8新引入的异步编程方式
使用方式
一、开启异步
supplyAsync(有返回值)
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> {
System.out.println("开始异步运行");
return "异步运行完成";
});
future.join(); // 等待异步任务完成并获取结果
}
runAsync(无返回值)
public static void main(String[] args) {
CompletableFuture<Void> future = CompletableFuture.runAsync(()-> {
System.out.println("开始异步运行");
});
future.join(); // 等待异步任务完成
}
默认是开启的异步守护线程,如果没有调用异步结果,主线程先结束的话,异步任务未完成也会直接结束。
调用异步结果,主线程会等待异步任务完成,获取结果再继续运行。
二、连接两个异步任务
thenCompose
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> {
System.out.println("开始异步运行1");
return "异步运行完成1";
}).thenCompose(result -> CompletableFuture.supplyAsync(()->{
System.out.println("异步任务1结果:" + result);
System.out.println("开始异步运行2");
return "异步运行完成2";
}));
future.join(); // 获取异步结果(得到的是2的结果)
}
三、做任务的后置处理
thenApply(有返回值)
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> {
System.out.println("开始异步运行1");
return "异步运行完成1";
}).thenApply(result -> {
System.out.println("异步任务1结果:" + result);
System.out.println("开始异步运行2");
return "异步运行完成2";
));
future.join(); // 获取异步结果(得到的是2的结果)
}
thenAccept(无返回值)
public static void main(String[] args) {
CompletableFuture<Void> future = CompletableFuture.supplyAsync(()-> {
System.out.println("开始异步运行1");
return "异步运行完成1";
}).thenAccept(result -> {
System.out.println("异步任务1结果:" + result);
System.out.println("开始异步运行2");
));
future.join(); // 等待异步任务完成
}
thenRun(无入参,无返回值)
public static void main(String[] args) {
CompletableFuture<Void> future = CompletableFuture.supplyAsync(()-> {
System.out.println("开始异步运行1");
return "异步运行完成1";
}).thenRun(() -> {
System.out.println("开始异步运行2");
));
future.join(); // 等待异步任务完成
}
四、组合处理
thenCombine(有返回值)
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> {
System.out.println("开始异步运行1");
return "异步运行完成1";
}).thenCombine(CompletableFuture.supplyAsync(()->{
System.out.println("开始异步运行2");
return "异步运行完成2";
}), (x, y) -> {
System.out.println("异步任务1结果:" + x);
System.out.println("异步任务2结果:" + y);
return "返回最终结果";
});
future.join(); // 获取异步结果(得到的是最终的结果)
}
任务1和任务2分别开了不同的线程运行。
thenAcceptBoth(无返回值)
public static void main(String[] args) {
CompletableFuture<Void> future = CompletableFuture.supplyAsync(()-> {
System.out.println("开始异步运行1");
return "异步运行完成1";
}).thenAcceptBoth(CompletableFuture.supplyAsync(()->{
System.out.println("开始异步运行2");
return "异步运行完成2";
}), (x, y) -> {
System.out.println("异步任务1结果:" + x);
System.out.println("异步任务2结果:" + y);
});
future.join(); // 等待异步任务完成
}
runAfterBoth(无入参,无返回值)
public static void main(String[] args) {
CompletableFuture<Void> future = CompletableFuture.supplyAsync(()-> {
System.out.println("开始异步运行1");
return "异步运行完成1";
}).runAfterBoth(CompletableFuture.supplyAsync(()->{
System.out.println("开始异步运行2");
return "异步运行完成2";
}), () -> {
System.out.println("开始异步运行3");
});
future.join(); // 等待异步任务完成
}
五、优先处理
applyToEither(有返回值)
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> {
System.out.println("开始异步运行1, 需要时间3s");
return "异步运行完成1";
}).applyToEither(CompletableFuture.supplyAsync(()->{
System.out.println("开始异步运行2, 需要时间2s");
return "异步运行完成2";
}), result -> result);
future.join(); // 获取异步结果(先处理完的结果)
}
acceptEither(无返回值)
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> {
System.out.println("开始异步运行1, 需要时间3s");
return "异步运行完成1";
}).acceptEither(CompletableFuture.supplyAsync(()->{
System.out.println("开始异步运行2, 需要时间2s");
return "异步运行完成2";
}), result -> {
System.out.println("处理结果:" + result);
});
future.join(); // 等待异步任务完成
}
runAfterEither(无入参,无返回值)
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> {
System.out.println("开始异步运行1, 需要时间3s");
return "异步运行完成1";
}).runAfterEither(CompletableFuture.supplyAsync(()->{
System.out.println("开始异步运行2, 需要时间2s");
return "异步运行完成2";
}), () -> {
System.out.println("后续操作");
});
future.join(); // 等待异步任务完成
}
在第一个异步任务完成后,等待就会停止,主线程会继续执行下去。
慢的异步任务也会继续执行完成,前提是主线程还没执行完。
因为异步任务使用的是守护线程,主线程已经执行完了,异步还未执行完成将看不到后续结果,因为整个程序已经结束。
六、批量处理
allOf
public static void main(String[] args) throws Exception {
List<CompletableFuture<Void>> completableFutures = IntStream.range(0, 10)
.mapToObj(index -> CompletableFuture.runAsync(() -> {
System.out.println(index + "do something ...");
}, executorService))
.collect(Collectors.toList());
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).join(); // 等待异步任务全部完成
}
启动了10个异步线程去处理任务,通过CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).join();等待所有的异步任务完成再继续。
要获取异步任务产生的结果:
public static void main(String[] args) throws Exception {
List<CompletableFuture<String>> completableFutures = IntStream.range(0, 10)
.mapToObj(index -> CompletableFuture.supplyAsync(() -> {
System.out.println(index + "do something ...");
return index + "异步任务完成";
}, executorService))
.collect(Collectors.toList());
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0]))
.thenRun(() -> {
completableFutures.stream().map(CompletableFuture::join).forEach(System.out::println);
}); // 等所有的任务完成后,再遍历获取处理所有的结果。
}
anyOf
public static void main(String[] args) throws Exception {
List<CompletableFuture<Void>> completableFutures = IntStream.range(0, 10)
.mapToObj(index -> CompletableFuture.runAsync(() -> {
System.out.println(index + "do something ...");
}, executorService))
.collect(Collectors.toList());
CompletableFuture.anyOf(completableFutures.toArray(new CompletableFuture[0])).join(); // 等待第一个异步任务完成,并获取结果
}
多个异步任务一起执行,等待第一个任务完成,并获取结果。
主程序会在得到第一个任务结果后马上往下执行,其他的异步任务不会停止,还会继续执行完。(前提是主线程还没执行完成)
七、异常处理
exceptionally(只接收异常,返回备用方案)
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> {
System.out.println("开始异步运行1, 需要时间3s");
return "异步运行完成1";
}).applyToEither(CompletableFuture.supplyAsync(()->{
System.out.println("开始异步运行2, 需要时间2s");
return "异步运行完成2";
}), result -> result).exceptionally(e -> {
System.out.println("异常处理");
return "备用方案";
});
future.join(); // 获取异步结果(出现异常了,返回备用方案)
}
handle(接收异常和结果,返回最终方案)
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> {
System.out.println("开始异步运行1, 需要时间3s");
return "异步运行完成1";
}).applyToEither(CompletableFuture.supplyAsync(()->{
System.out.println("开始异步运行2, 需要时间2s");
return "异步运行完成2";
}), result -> result).handle((e, s) -> {
if(e != null) {
System.out.println("异常处理:" + e.getMessage());
}
System.out.println("未出异常, 结果:" + s);
return "最终方案";
});
future.join(); // 获取异步结果(返回最终方案)
}
whenComplete(接收异常和结果,无返回值)
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> {
System.out.println("开始异步运行1, 需要时间3s");
return "异步运行完成1";
}).applyToEither(CompletableFuture.supplyAsync(()->{
System.out.println("开始异步运行2, 需要时间2s");
return "异步运行完成2";
}), result -> result).whenComplete((s, e) -> {
if(e != null) {
System.out.println("异常处理:" + e.getMessage());
}
System.out.println("未出异常, 结果:" + s);
});
future.join(); // 获取异步结果(whenComplete不影响异步结果)
}
八、xxx和xxxAsync(e: thenApply() 和thenApplyAsync())
xxx
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> {
System.out.println("开始异步运行1");
return "异步运行完成1";
}).thenApply(result -> {
System.out.println("异步任务1结果:" + result);
System.out.println("开始异步运行2");
return "异步运行完成2";
));
future.join(); // 获取异步结果(得到的是2的结果)
}
另起一个线程,先完成异步任务1,再完成异步任务2。
xxxAsync
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(()-> {
System.out.println("开始异步运行1");
return "异步运行完成1";
}).thenApplyAsync(result -> {
System.out.println("异步任务1结果:" + result);
System.out.println("开始异步运行2");
return "异步运行完成2";
));
future.join(); // 获取异步结果(得到的是2的结果)
}
另起一个线程,完成异步任务1,再起一个线程完成异步任务2
九、线程池
默认线程池
前文一直在说,线程是守护线程,这里讲讲是为什么。(下面会出现大量源码)
asyncPool默认线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
return asyncSupplyStage(asyncPool, supplier);
}
默认线程池的创建取决于useCommonPool参数
private static final Executor asyncPool = useCommonPool ?
ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
useCommonPool参数又取决于ForkJoinPool的commonPoolParallelism值
private static final boolean useCommonPool =
(ForkJoinPool.getCommonPoolParallelism() > 1);
java.util.concurrent.ForkJoinPool类中有段静态方法
static {
// initialize field offsets for CAS etc
......
common = java.security.AccessController.doPrivileged
(new java.security.PrivilegedAction<ForkJoinPool>() {
public ForkJoinPool run() { return makeCommonPool(); }});
int par = common.config & SMASK; // report 1 even if threads disabled
commonParallelism = par > 0 ? par : 1;
}
commonParallelism的值和common.config有关
common是啥就要看看makeCommonPool()了
private static ForkJoinPool makeCommonPool() {
final ForkJoinWorkerThreadFactory commonPoolForkJoinWorkerThreadFactory =
new CommonPoolForkJoinWorkerThreadFactory();
int parallelism = -1;
ForkJoinWorkerThreadFactory factory = null;
UncaughtExceptionHandler handler = null;
try { // ignore exceptions in accessing/parsing properties
String pp = System.getProperty
("java.util.concurrent.ForkJoinPool.common.parallelism");
String fp = System.getProperty
("java.util.concurrent.ForkJoinPool.common.threadFactory");
String hp = System.getProperty
("java.util.concurrent.ForkJoinPool.common.exceptionHandler");
if (pp != null)
parallelism = Integer.parseInt(pp);
if (fp != null)
factory = ((ForkJoinWorkerThreadFactory)ClassLoader.
getSystemClassLoader().loadClass(fp).newInstance());
if (hp != null)
handler = ((UncaughtExceptionHandler)ClassLoader.
getSystemClassLoader().loadClass(hp).newInstance());
} catch (Exception ignore) {
}
if (factory == null) {
if (System.getSecurityManager() == null)
factory = commonPoolForkJoinWorkerThreadFactory;
else // use security-managed default
factory = new InnocuousForkJoinWorkerThreadFactory();
}
if (parallelism < 0 && // default 1 less than #cores
(parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
parallelism = 1;
if (parallelism > MAX_CAP)
parallelism = MAX_CAP;
return new ForkJoinPool(parallelism, factory, handler, LIFO_QUEUE,
"ForkJoinPool.commonPool-worker-");
}
parallelism的值有两个影响
系统配置java.util.concurrent.ForkJoinPool.common.parallelism
电脑cup核心数
String pp = System.getProperty
("java.util.concurrent.ForkJoinPool.common.parallelism");
if (pp != null)
parallelism = Integer.parseInt(pp);
parallelism = Runtime.getRuntime().availableProcessors() - 1
asyncPool最终值
一顿分析,parallelism一般等于电脑cup核心数-1
asyncPool = ForkJoinPool.commonPool();
ForkJoinPool.commonPool()
public static ForkJoinPool commonPool() {
// assert common != null : "static init error";
return common;
}
common的定义在上面已经展示了
最后返回的是这样一个对象
return new ForkJoinPool(parallelism, factory, handler, LIFO_QUEUE,
"ForkJoinPool.commonPool-worker-");
其中factory就是创建线程的工厂,他的相关定义
String fp = System.getProperty
("java.util.concurrent.ForkJoinPool.common.threadFactory");
if (fp != null)
factory = ((ForkJoinWorkerThreadFactory)ClassLoader.
getSystemClassLoader().loadClass(fp).newInstance());
//-----------------------------------------------------------------------------------
if (factory == null) {
if (System.getSecurityManager() == null)
factory = defaultForkJoinWorkerThreadFactory;
else // use security-managed default
factory = new InnocuousForkJoinWorkerThreadFactory();
}
//-----------------------------------------------------------------------------------
defaultForkJoinWorkerThreadFactory =
new DefaultForkJoinWorkerThreadFactory();
默认情况下,factory就是DefaultForkJoinWorkerThreadFactory
DefaultForkJoinWorkerThreadFactory
static final class DefaultForkJoinWorkerThreadFactory
implements ForkJoinWorkerThreadFactory {
public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
return new ForkJoinWorkerThread(pool);
}
}
ForkJoinWorkerThread(ForkJoinPool pool)
protected ForkJoinWorkerThread(ForkJoinPool pool) {
// Use a placeholder until a useful name can be set in registerWorker
super("aForkJoinWorkerThread");
this.pool = pool;
this.workQueue = pool.registerWorker(this);
}
registerWorker(this)
final WorkQueue registerWorker(ForkJoinWorkerThread wt) {
UncaughtExceptionHandler handler;
wt.setDaemon(true); // configure thread
if ((handler = ueh) != null)
wt.setUncaughtExceptionHandler(handler);
WorkQueue w = new WorkQueue(this, wt);
int i = 0; // assign a pool index
int mode = config & MODE_MASK;
int rs = lockRunState();
try {
WorkQueue[] ws; int n; // skip if no array
if ((ws = workQueues) != null && (n = ws.length) > 0) {
int s = indexSeed += SEED_INCREMENT; // unlikely to collide
int m = n - 1;
i = ((s << 1) | 1) & m; // odd-numbered indices
if (ws[i] != null) { // collision
int probes = 0; // step by approx half n
int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2;
while (ws[i = (i + step) & m] != null) {
if (++probes >= n) {
workQueues = ws = Arrays.copyOf(ws, n <<= 1);
m = n - 1;
probes = 0;
}
}
}
w.hint = s; // use as random seed
w.config = i | mode;
w.scanState = i; // publication fence
ws[i] = w;
}
} finally {
unlockRunState(rs, rs & ~RSLOCK);
}
wt.setName(workerNamePrefix.concat(Integer.toString(i >>> 1)));
return w;
}
上面DefaultForkJoinWorkerThreadFactory的newThread方法返回的就是一个新的线程
在创建新的线程时,其构造函数中pool.registerWorker(this);该方法传入线程本身
在这个方法中看到wt.setDaemon(true); 设置,就将该线程设置为守护线程了(wt就是线程本身)
自定义线程池
我们可以通过设置系统参数来改变默认线程池的一些配置,但是不推荐。因为这样的修改影响的是整个程序,不好控制。
CompletableFuture的方法中是有参数提供,让我们使用自定义线程池的。
看下来你会发现,xxxAsync()方法都是成双出现的,是有重载的,e :
runAsync(Runnable runnable);
runAsync(Runnable runnable, Executor executor);
Executor参数就可以传我们自定义的线程池
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println("do something ......");
}, executorService);
future.join();
executorService.shutdown();
}
使用完线程池,记得关闭,线程池中默认创建的线程不是守护线程,不关闭的话,你的程序不会结束。
自定义线程池推荐使用new ThreadPoolExecutor();而不是直接使用工具提供的四种线程池,他们都存在各自的缺陷,详细信息可以查看线程池相关的资料,要按自己的业务需要,创建适合的线程池。