Lectura relacionada:
Programación concurrente Java (1) Mapa de conocimiento
Programación concurrente Java (2)
Programación concurrente Java atómica (3) Visibilidad
Programación concurrente Java (4)
Programación concurrente Java ordenada (5) Descripción general de los métodos de creación de hilos
Introducción a la programación concurrente Java (6) Uso de sincronización
Introducción a la programación concurrente de Java (7) Escenarios de uso y espera fáciles de entender y notificación
Introducción a la programación concurrente de Java (8) Ciclo de vida del hilo
Introducción a la programación concurrente de Java (9) Punto muerto y punto muerto
Introducción a la programación concurrente de Java (10) Optimización de bloqueo
Java Introducción a la programación concurrente (once) Escenarios de limitación de corriente e implementación del limitador de corriente de resorte de
la programación concurrente de Java (doce) Plantilla de código de modo de productor y consumidor
Programación concurrente de Java (trece) Bloqueo de lectura / escritura y plantilla de caché
Programación concurrente de Java Introducción (catorce)
Escenario de la aplicación CountDownLatch Introducción a la programación concurrente de Java (quince) Escenario de la aplicación CyclicBarrier
Introducción a la programación concurrente de Java (dieciséis) segundos para comprender la diferencia entre el grupo de subprocesos
Introducción a la programación concurrente de Java (diecisiete) un subproceso de imagen maestro clases comunes e interfaces
Concurrencia de Java Introducción a la programación (18) Nueva discusión sobre seguridad de subprocesos
1. Introducción a CompleteFeature
CompleteFeature es una mejora de Feature. Feature solo puede manejar tareas asincrónicas simples, y CompleteFeature puede combinar múltiples tareas asincrónicas en una combinación compleja, admitiendo ejecución en serie, ejecución paralela, y agregación, o agregación, para que pueda manejar tareas relacionadas complejas Realizar la programación.
2. Escenarios comerciales compatibles con CompleteFeature
2.1. Tareas en serie
La tarea en serie se refiere a que la tarea B espera a que la tarea A complete la ejecución. La tarea en serie tiene los siguientes atributos:
Atributos | Descripción |
---|---|
Se puede obtener un resultado | La tarea B puede obtener el resultado de ejecución de la tarea A como parámetro |
B tiene un valor de retorno | Si la tarea B tiene un valor de retorno, puede devolver el resultado de la ejecución a través del valor de retorno |
Disponible una excepción | La tarea B puede obtener la excepción lanzada por la tarea A |
Una terminación anormal | Cuando la tarea A arroja una excepción, si el programa terminará, si terminará, el programa saldrá, la tarea B no se ejecutará, de lo contrario el programa no saldrá y continuará la ejecución. |
Los métodos de tareas en serie compatibles con CompleteFeature son los siguientes:
Método | Se puede obtener un resultado | B tiene un valor de retorno | Disponible una excepción | Una terminación anormal |
---|---|---|---|---|
entonces corre | No | No | No | Si |
entoncesAplicar | Si | Si | No | Si |
entonces Aceptar | Si | No | No | Si |
luegoComponer | Si | Si | No | Si |
whenComplete | Si | No | Si | No |
excepcionalmente | No | Si | Si | No |
encargarse de | Si | Si | Si | No |
Resumen:
- La tarea usará los primeros cuatro métodos sin lanzar una excepción; de lo contrario, use los últimos tres métodos.
- excepcionalmente equivalente a la parte catch de try {} catch {}, cuando Complete y handle son equivalentes a la parte catch y final de try {} catch {} finalmente {}, la diferencia es que uno tiene un valor de retorno y el otro no tiene ningún valor de retorno.
- La diferencia entre thenApply y thenCompose es que thenCompose devuelve CompletableFuture en la tarea B, puede consultar los siguientes ejemplos para comparar las diferencias.
1.2. Y convergencia
Y la relación de agregación significa que la tarea C necesita esperar a que la tarea A o la tarea B se ejecuten antes de ejecutarse. CompleteFeature admite esta relación de la siguiente manera:
Método | C recibe el valor de retorno de A o B como parámetro | C tiene un valor de retorno |
---|---|---|
entoncesCombine | Si | Si |
entoncesAceptarBoth | Si | No |
runAfterBoth | No | No |
1.3. O convergencia
O la relación de agregación significa que la tarea C espera a que se ejecute una de las tareas A o B, es decir, C solo necesita esperar a que se ejecute la primera tarea. CompleteFeature admite esta relación de la siguiente manera:
Método | C recibe el valor de retorno de A o B como parámetro | C tiene un valor de retorno |
---|---|---|
applyToEither | Si | Si |
aceptar Cualquiera | Si | No |
runAfterEither | No | No |
1.4. Multitarea
CompletableFuture proporciona dos métodos multitarea:
Método | Descripción |
---|---|
cualquiera de | Después de ejecutar cualquiera de las múltiples tareas, finaliza y se puede obtener el valor de retorno de la primera tarea ejecutada. |
todo | Se completan varias tareas después de la ejecución y no se puede obtener el valor de retorno de ninguna tarea |
Los valores de retorno de todos los métodos anteriores son CompletableFuture, por lo que puede continuar llamando a los métodos descritos anteriormente para realizar una combinación de tareas y combinar flujos de procesamiento de tareas más complejos.
1.5. Método familia
La última tarea en el método anterior se ejecuta en el mismo subproceso que la tarea anterior. También hay un conjunto de métodos en CompletableFuture para que la última tarea se ejecute en un nuevo subproceso, siempre que se agregue el sufijo Async al método original, por ejemplo:
Sincronización | Asincrónico |
---|---|
entoncesAplicar | thenApplyAsync |
entonces Aceptar | thenAcceptAsync |
entonces corre | thenRunAsync |
luegoComponer | thenComposeAsync |
Para más detalles, consulte el código fuente.
2. Ejemplos de código
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompleteFeatureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
simpleTask();
serialTask();
andTask();
orTask();
complexTask();
sleep(2000); // 等待子线程结束
System.out.println("end.");
}
private static void simpleTask() throws ExecutionException, InterruptedException {
// 1. runAsync 执行一个异步任务,没有返回值
CompletableFuture.runAsync(()-> System.out.println("1. runAsync"));
sleep(100);
// 2. supplyAsync 执行一个异步任务,有返回值
CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{
System.out.println("2.1 supplyAsync task be called");
sleep(100);
return "2.2 supplyAsync return value";
});
System.out.println("2.3 after supplyAsync");
System.out.println(future.get());
sleep(200);
}
private static void serialTask() throws ExecutionException, InterruptedException {
// 3. thenRun
CompletableFuture.supplyAsync(()->{
System.out.println("3.1 supplyAsync begin");
sleep(100); // 用于证明B等待A结束才会执行
return "3.2 supplyAsync end";
}).thenRun(()->{
System.out.println("3.3 thenRun be called.");
});
sleep(200);
// 4. thenApply
CompletableFuture<String> future4 = CompletableFuture.supplyAsync(()->{
sleep(100);
return "4.1 apple";
}).thenApply(returnVal->{
return "4.2 " + returnVal + "-苹果";
});
System.out.println("4.3 get: " + future4.get());
sleep(100);
// 5. thenAccept
CompletableFuture.supplyAsync(()->{
sleep(100);
return "5.1 orange";
}).thenAccept(returnVal->{
System.out.println("5.2 " + returnVal + "-桔子");
});
sleep(100);
// 6. thenCompose
CompletableFuture<String> future6 = CompletableFuture.supplyAsync(()->{
sleep(100);
return "6.1 apple";
}).thenCompose((returnVal)->{
return CompletableFuture.supplyAsync(()->{
return "6.2 " + returnVal;
});
});
System.out.println("6.3 get: " + future6.get());
sleep(100);
// 7. whenComplete
CompletableFuture.supplyAsync(()->{
sleep(100);
if (true) { //修改boolean值观察不同结果
return "7.1 return value for whenComplete";
} else {
throw new RuntimeException("7.2 throw exception for whenComplete");
}
}).whenComplete((returnVal, throwable)->{
System.out.println("7.2 returnVal: " + returnVal); // 可以直接拿到返回值,不需要通过future.get()得到
System.out.println("7.3 throwable: " + throwable); // 异步任务抛出异常,并不会因为异常终止,而是会走到这里,后面的代码还会继续执行
});
sleep(100);
// 8. exceptionally
CompletableFuture<String> future8 = CompletableFuture.supplyAsync(()->{
sleep(100);
if (false) { //修改boolean值观察不同结果
return "8.1 return value for exceptionally";
} else {
throw new RuntimeException("8.2 throw exception for exceptionally");
}
}).exceptionally(throwable -> {
throwable.printStackTrace();
return "8.3 return value after dealing exception.";
});
System.out.println("8.4 get: " + future8.get());
sleep(100);
// 9. handle
CompletableFuture<String> future9 = CompletableFuture.supplyAsync(()->{
sleep(100);
if (false) { //修改boolean值观察不同结果
return "9.1 return value for handle";
} else {
throw new RuntimeException("9.2 throw exception for handle");
}
}).handle((retuanVal, throwable)->{
System.out.println("9.3 retuanVal: " + retuanVal);
System.out.println("9.4 throwable: " + throwable);
return "9.5 new return value.";
});
System.out.println("9.6 get: " + future9.get());
sleep(100);
}
private static void andTask() throws ExecutionException, InterruptedException {
// 10. thenCombine 合并结果
CompletableFuture<String> future10 = CompletableFuture.supplyAsync(()->{
sleep(100);
return "10.1 TaskA return value";
}).thenCombine(CompletableFuture.supplyAsync(()->{
sleep(100);
return "10.2 TaskB return value";
}), (taskAReturnVal, taskBReturnVal) -> taskAReturnVal + taskBReturnVal);
System.out.println("10.3 get: " + future10.get());
sleep(200);
// 11. thenAcceptBoth
CompletableFuture.supplyAsync(()->{
sleep(100);
return "11.1 TaskA return value";
}).thenAcceptBoth(CompletableFuture.supplyAsync(()->{
sleep(100);
return "11.2 TaskB return value";
}), (taskAReturnVal, taskBReturnVal) -> System.out.println(taskAReturnVal + taskBReturnVal));
sleep(200);
// 12. runAfterBoth A,B都执行完后才执行C,C不关心前面任务的返回值
CompletableFuture.supplyAsync(()->{
sleep(200); // 虽然这个任务先执行,但是执行时间比下面的任务长,所以最后会使用下面的返回结果
System.out.println("12.1 TaskA be called.");
return "12.2 TaskA return value";
}).runAfterBoth(CompletableFuture.supplyAsync(()->{
sleep(100);
System.out.println("12.3 TaskB be called.");
return "12.4 TaskB return value";
}), () -> System.out.println("12.5 TaskC be called."));
sleep(300);
}
private static void orTask() throws ExecutionException, InterruptedException {
// 13. applyToEither 使用A,B两个异步任务优先返回的结果
CompletableFuture<String> future13 = CompletableFuture.supplyAsync(()->{
sleep(200); // 虽然这个任务先执行,但是执行时间比下面的任务长,所以最后会使用下面的返回结果
System.out.println("13.1 TaskA be called"); // 用于证明拿到B的结果后,A还会继续执行,并不会终止
return "13.2 TaskA return value";
}).applyToEither(CompletableFuture.supplyAsync(()->{
sleep(100);
return "13.3 TaskB return value";
}), (returnVal) -> returnVal);
System.out.println("13.4 get: " + future13.get());
sleep(300);
// 14. acceptEither 使用A,B两个异步任务优先返回的结果
CompletableFuture.supplyAsync(()->{
sleep(200); // 虽然这个任务先执行,但是执行时间比下面的任务长,所以最后会使用下面的返回结果
return "14.1 TaskA return value";
}).acceptEither(CompletableFuture.supplyAsync(()->{
sleep(100);
return "14.2 TaskB return value";
}), (returnVal) -> System.out.println(returnVal));
sleep(300);
// 15. runAfterEither A,B任意一个执行完后就执行C,C不关心前面任务的返回值
CompletableFuture.supplyAsync(()->{
sleep(200); // 虽然这个任务先执行,但是执行时间比下面的任务长,所以最后会使用下面的返回结果
System.out.println("15.1 TaskA be called.");
return "15.2 TaskA return value";
}).runAfterEither(CompletableFuture.supplyAsync(()->{
sleep(100);
System.out.println("15.3 TaskB be called.");
return "15.4 TaskB return value";
}), () -> System.out.println("15.5 TaskC be called."));
sleep(300);
}
private static void complexTask() throws ExecutionException, InterruptedException {
// 16. anyOf
CompletableFuture future16 = CompletableFuture.anyOf(CompletableFuture.supplyAsync(()->
{
sleep(300);
System.out.println("16.1 TaskA be called.");
return "16.2 TaskA return value.";
}), CompletableFuture.supplyAsync(()->{
sleep(100);
System.out.println("16.3 TaskB be called.");
return "16.4 TaskB return value.";
}));
System.out.println("16.5 get: " + future16.get());
sleep(400);
// 17. allOf
CompletableFuture<Void> future17 = CompletableFuture.allOf(CompletableFuture.supplyAsync(()->
{
sleep(300);
System.out.println("17.1 TaskA be called.");
return "17.2 TaskA return value.";
}), CompletableFuture.supplyAsync(()->{
sleep(100);
System.out.println("17.3 TaskB be called.");
return "17.4 TaskB return value.";
}));
System.out.println("17.5 get: " + future17.get()); // allOf没有返回值
}
private static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
}
复制代码
3. Resumen
CompleteFeature admite la programación compleja de tareas asincrónicas, admite múltiples tareas en serie, paralelas y de agregación.Cuando varias tareas asincrónicas tienen dependencias, la programación de tareas a través de CompleteFeature puede simplificar enormemente el código y mejorar el rendimiento de la ejecución.
fin.