【2023】 Introducción al caso del código de uso de CompletebleFuture a escenarios de uso de pasantías (tutorial a nivel de niñera)

1. Introducción

1. Información general

CompletableFutureEs una herramienta de programación asincrónica introducida en Java 8 y se encuentra java.util.concurrent en el paquete. Proporciona una manera conveniente de realizar tareas asincrónicas y realizar acciones apropiadas cuando se completan las tareas.

  • CompletableFutureEs Futureuna ampliación y potenciación del derecho; CompletableFuturealgo que se puede lograr o fracasar Future. Proporciona un mecanismo general para manejar los resultados de operaciones asincrónicas, incluido el manejo de la finalización de tareas asincrónicas, el manejo de excepciones y la combinación de los resultados de múltiples tareas asincrónicas.
  • Y al implementar CompletionStage, se logra la capacidad de orquestar tareas: cuando se ejecuta una determinada etapa, las etapas posteriores se pueden ejecutar hacia abajo.
  • Durante la ejecución asincrónica, si el grupo de subprocesos no está definido, el grupo de subprocesos predeterminado sí lo está. ForkJoinPool.commonPool()Sin embargo, en el desarrollo real general, es mejor definir el grupo de subprocesos usted mismo para evitar problemas de bloqueo causados ​​por el hecho de que los subprocesos del grupo de subprocesos predeterminados estén llenos.

2. Métodos comúnmente utilizados

CompletableFutureEl método no Asynctermina en , lo que significa que la Acción usa el mismo subproceso para ejecutarse; puede Asyncusar otros subprocesos para ejecutarse (si se usa el mismo grupo de subprocesos, también puede ser seleccionado por el mismo subproceso para su ejecución).

nombre del método describir valor de retorno método estático
suministroAsync Ejecutar asincrónicamente una tarea con un valor de retorno CompletableFuture tener
ejecutarAsync Ejecutar asincrónicamente una tarea sin valor de retorno CompletableFuture ninguno
unirse Obtenga el valor de retorno de CompletableFuture de forma asincrónica y genere una excepción no verificada. tener No
conseguir Obtenga el valor de retorno de CompletableFuture de forma asincrónica. Lo que se genera es una excepción marcada, que debe manejarse manualmente (lanzar o intentar capturar). tener No
cuando esté completo Se utiliza para realizar la operación especificada después de que se completa CompletableFuture (normal o anormalmente) tener No
excepcionalmente La tarea CompletableFuture se ejecuta cuando ocurre una excepción y no se ejecuta cuando no ocurre ninguna excepción. tener No
luego aplicar Cuando se completa la tarea actual, ejecuta una función y devuelve un nuevo CompletableFuture tener No
luego componer Cuando se completa la tarea actual, ejecuta una función y devuelve un nuevo CompletableFuture (diferente de los parámetros de entrada de thenApply) tener No
luegoAceptar Cuando se complete la tarea anterior, ejecute una función de consumidor sin valor de retorno ninguno No
luegoAceptarAmbos Cuando se ejecutan ambos CompletableFutures, se realiza la operación especificada y no hay ningún valor de retorno. ninguno No
entonces corre Cuando se completa la ejecución de la tarea de la etapa anterior, una tarea sin ningún parámetro de entrada se ejecuta de forma asincrónica; ninguno No
luego combinar Combina los resultados de dos CompletableFutures y devuelve un nuevo CompletableFuture tener No
aplicar a cualquiera Compare y procese las dos tareas que se ejecutan primero, utilice los resultados de cualquier tarea que se utilice para procesar y devuelva los nuevos resultados. tener No
aceptarCualquiera Compare y procese las dos tareas que se ejecutan primero y utilice los resultados de cualquier tarea que se utilice para el procesamiento. Los resultados se consumen directamente y no se devuelven nuevos resultados. ninguno No
ejecutar después de cualquiera Cuál de las dos tareas a comparar y procesar se ejecuta primero, pasa directamente a la siguiente operación y no le importa el resultado de ejecución del paso anterior y no regresa. ninguno No
todo de Recibe una serie de objetos de tareas futuras y devuelve una nueva tarea cuando se completan todas las tareas. ninguno
cualquiera de Recibe una matriz de objetos de tareas futuras. Cuando se completa una tarea, se devuelve la tarea. tener

Estos métodos se utilizan para crear, combinar y procesar instancias de CompletableFuture para permitir la programación asincrónica. Cada método tiene diferentes funciones y usos, y puedes elegir el método apropiado para construir según tus necesidades específicas.

2. Uso del método

1. Operación asincrónica

1.1 Crear tareas (runAsync | SupplyAsync)

ejecutarAsync

runAsync()Sin valor de retorno, el parámetro es un tipo de función ejecutable y se puede especificar el grupo de subprocesos; si no se especifica, el grupo de subprocesos predeterminado ForkJoinPool.commonPool() se usará internamente.


        Runnable runnable = () -> {
    
    

            System.out.println("无返回值的异步任务"+Thread.currentThread().getName());
        };
//			非简写方式
        CompletableFuture.runAsync(runnable).join();

suministroAsync

supplyAsyncHay un valor de retorno y otros usos son básicamente los mismos que runAsync (), puede especificar el tipo al regresar.

//			简写方式
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    
    
            System.out.println("有返回值的异步任务"+Thread.currentThread().getName());
            try {
    
    
                Thread.sleep(5000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            return "Hello World!";
        }, Executors.newFixedThreadPool(1));   //指定线程池
        String join = future.join();
        System.out.println(Thread.currentThread().getName()+"结果"+join);

1.2 Obtener resultados (obtener | unirse)

Tanto get () como join se utilizan para obtener el valor de retorno de CompletableFuture de forma asincrónica. El método join () genera una excepción de desmarcación (es decir, una excepción no verificada) y no obliga a los desarrolladores a lanzarla. El método get () arroja excepciones marcadas. El usuario debe manejar manualmente ExecutionException e InterruptedException (lanzar o intentar capturar)

1.3 Manejo de excepciones (cuando se completa | excepcionalmente)

cuando esté completo

Se utiliza para CompletableFuturerealizar operaciones específicas después de la finalización (finalización normal o anormal); CompletableFutureherramienta útil para realizar algunas operaciones adicionales una vez finalizada, ya sea que se complete con éxito o se produzca una excepción (equivalente a la parte final), se devolverá la excepción y el resultado. Uno, el otro será nulo.

  • Escenario: Grabar registros y limpiar recursos
  • Código
         CompletableFuture.supplyAsync(() -> {
    
    
            System.out.println("无返回值的异步任务线程===="+Thread.currentThread().getName());
            return "----德玛西亚!-----";
        }).whenComplete((u, e) -> {
    
     //(u:没有异常时返回的结果,e:有异常时返回的结果)
            System.out.println("future线程======" + Thread.currentThread().getName());

            System.out.println("执行结果:"+u);
            System.out.println("异常输出:" + e);
        }).join();
  • salida de registro
    Insertar descripción de la imagen aquí

excepcionalmente

Excepcionalmente se pueden usar juntos: solo cuando ocurre una excepción, se ejecutarán las tareas excepcionalmente (equivalente a la parte de captura)

  • Código:
        CompletableFuture<String>  future = CompletableFuture.supplyAsync(() -> {
    
    
                try {
    
    
                    Thread.sleep(100);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                Integer i= 10/0;    //模拟一个异常
                return "Hello World!";
         }).whenCompleteAsync((u, e) -> {
    
       //(u:没有异常时返回的结果,e:有异常时返回的结果)

            try {
    
    
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException ex) {
    
    
                ex.printStackTrace();
            }
            System.out.println("执行结果:"+u); 
            System.out.println("异常输出:" + e);
            
        }).exceptionally(t -> {
    
        //进行异常处理,无异常时不会执行下面的处理

            System.out.println("执行失败进行异常处理!");
            return "异常XXXX--" + t;
        });

        System.out.println("结果:"+future.join());
  • Salida del registro:
    • Salida cuando ocurre una excepción:Insertar descripción de la imagen aquí
    • Salida cuando no hay excepción:
      Insertar descripción de la imagen aquí

2. Uso de escenarios

2.1 Conversión de resultados (luego Aplicar | luego Componer)

thenApplyy thenComposeambos se utilizan para operaciones en cadena, pero la forma de ingresar parámetros es diferente.
Función: generalmente se utiliza para procesar algunos resultados que deben procesarse de forma asincrónica. Este método no cambia el tipo de resultado de Future. El método de ejecución es como una canalización, se ejecuta paso a paso. El uso es el mismo que el de una secuencia. Se utiliza para realizar algunas operaciones intermedias; por ejemplo
: puede convertir un resultado de cadena a mayúsculas o minúsculas, o realizar algunos cálculos con números. Tales como: futuro1->futuro2->futuro3

luego aplicar

thenApply: Recibe una función como parámetro, usa la función para procesar CompletableFutureel resultado de la llamada anterior y devuelve un objeto Future con el resultado del procesamiento.

  • Código:
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
    
    
            int result = new Random().nextInt(5) ;
            try {
    
    
                TimeUnit.SECONDS.sleep(result);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("建立人物模型,耗时:"+result);
            return result;
        }, Executors.newFixedThreadPool(5));

//        thenApply: 接收一个函数作为参数,使用该函数处理上一个CompletableFuture调用的结果,并返回一个具有处理结果的Future对象

        CompletableFuture<Integer> future2 = future1.thenApply(number -> {
    
      //把future1的结果作为入参
            int result = new Random().nextInt(5) ;
            try {
    
    
                TimeUnit.SECONDS.sleep(result);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }

            System.out.println("加载模型骨骼,耗时:"+result);
            return result+number;
        });
        
        System.out.println("全部加载完成,耗时:"+future2.join()+"y");
  • Salida del registro:
    Insertar descripción de la imagen aquí

luego componer

thenCompose: El parámetro es una CompletableFuturefunción que devuelve una instancia (y el parámetro de esta instancia es el resultado del paso de cálculo anterior), y no hay diferencia en otros usos thenApply.

  • Código:
//			拼接前面thenApply部分的代码
        CompletableFuture<Integer> future3 = future2.thenCompose(param ->
                CompletableFuture.supplyAsync(() -> {
    
    
                    int result = new Random().nextInt(5) ;
                    try {
    
    
                        TimeUnit.SECONDS.sleep(result);
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }

                    System.out.println("加载模型皮肤,耗时:"+result);
                    return result+param;
                })
        );
          不简写的方式
//        CompletableFuture<Integer> future4 = future2.thenCompose(new Function<Integer, CompletionStage<Integer>>() {
    
    
//            @Override
//            public CompletionStage<Integer> apply(Integer param) {
    
    
//                return CompletableFuture.supplyAsync(new Supplier<Integer>() {
    
    
//                    @Override
//                    public Integer get() {
    
    
//                        int result = new Random().nextInt(5);
//                        try {
    
    
//                            TimeUnit.SECONDS.sleep(result);
//                        } catch (InterruptedException e) {
    
    
//                            e.printStackTrace();
//                        }
//                        System.out.println("加载模型皮肤,耗时:" + result);
//                        return result + param;
//                    }
//                });
//            }
//        });

        System.out.println("全部加载完成,耗时:"+future3.join()+"y");
  • Salida del registro:
    Insertar descripción de la imagen aquí

2.2 Consumo de resultados (luegoAceptar | luegoAceptarAmbos | luegoEjecutar)

luegoAceptar

thenAcceptSe utiliza para procesar de forma asincrónica los resultados de la tarea futura anterior y consumir los resultados sin devolver un valor
: por ejemplo, completar algunas operaciones requiere una condición previa y la ejecución asincrónica no necesita bloquear el hilo actual y se puede procesar simultáneamente a través de ejecución asincrónica de múltiples tareas

    public static void main(String[] args) {
    
    
//        消费之前,有返回Integer
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
    
    
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            int number = new Random().nextInt(10);
            System.out.println("加载商城页面" + number);
            return number;
        });
        System.out.println("商城页面加载成功:==="+future1.join()+"===继续加载商城内置页面!");


        CompletableFuture<Void> future2 = future1.thenAcceptAsync(number -> {
    
      //结果消费掉之后会没有返回值
            try {
    
    
                Thread.sleep(2000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            int n2 = number * 2;
            System.out.println("加载商城英雄页面:" + n2);
        });
        CompletableFuture<Void> future3 = future1.thenAcceptAsync(number -> {
    
      //结果消费掉之后会没有返回值
            try {
    
    
                Thread.sleep(2000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            int n2 = number * 3;
            System.out.println("加载商城皮肤页面:" + n2);
        });
        future2.join();
        future3.join();
        System.out.println("商城内置页面也加载成功:");
    }

luegoAceptarAmbosAsync

thenAcceptBothAsyncConsumirá los resultados de dos futuros, x es el actual e y es el
parámetro de entrada. No hay valor de retorno: se usa principalmente cuando es necesario completar dos tareas anteriores y luego consumir los resultados de las dos tareas anteriores para ejecute la tarea thenAcceptBoth (Cabe señalar que no se puede confirmar el orden de ejecución de las tareas predecesoras de este método)

  • Código:
        //        消费之前,有返回Integer
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
    
    
            int number = new Random().nextInt(10);
            System.out.println("工商银行储蓄卡余额:" + number);
            return number;
        });
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
    
    
            int number = new Random().nextInt(10);
            System.out.println("工商银行信用卡余额:" + number);
            return number;
        });

//        thenAcceptBothAsync会消费两个future的结果,x当前的,y入参的,无返回值
//                作用:主要用于当需要两个前置任务完成后,
//                  再消费两个前置任务的结果去执行thenAcceptBoth的任务(需要注意的是该方法的前置任务的执行顺序是无法确认的)

         future1.thenAcceptBothAsync(future2, (x, y) ->  //会消费掉两个前置任务的结果
                System.out.println("工商银行总余额:" + (x + y))
        );
  • Salida del registro:
    Insertar descripción de la imagen aquí

entonces corre

thenRunSe utiliza principalmente para ejecutar de forma asincrónica una tarea sin ningún parámetro de entrada después de completar la tarea anterior; generalmente se usa para limpieza, registro, cierre de recursos, liberación de bloqueos, etc.

  • Código:
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
    
    
            System.out.println(Thread.currentThread().getName());
            int number = new Random().nextInt(10);

            System.out.println("初始值:" + number);

            return number;
        });

//        thenRun:主要在前任务执行完成后异步执行一个不带任何输入参数的任务;一般用于某些清理,日志记录,关闭资源、释放锁等
        future1.thenRun(()->{
    
    
            System.out.println(Thread.currentThread().getName()+"执行run关闭资源");
        });
  • Salida del registro:
    Insertar descripción de la imagen aquí

2.3 Combinación de tareas (luego Combinar)

luego combinar

thenCombine: thenAcceptBothDe manera similar al uso, los resultados de dos futuros previos a la tarea se combinan y se usan para el procesamiento final, pero la thenCombinecombinación se procesa y luego se devuelve un nuevo valor.
Escenario: generalmente se usa para la adquisición y combinación de datos en paralelo y algunas conversiones y combinaciones de datos.

  • Código
        int i = 10;
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
    
    
            int number = new Random().nextInt(10) * i;
            System.out.println("获取用户的信息:" + number);
            return number;
        });

        CompletableFuture<Integer> future2 =CompletableFuture.supplyAsync(()->{
    
    
        int number = new Random().nextInt(10) * i;
        System.out.println("获取用户的订单信息:"+number);
        return number;
        });
        
        //不简写写法
//        CompletableFuture<Integer> result = future1
//                .thenCombine(future2, new BiFunction<Integer, Integer, Integer>() {
    
    
//                    @Override
//                    public Integer apply(Integer x, Integer y) {
    
    
//                        return x + y;
//                    }
//                });

//       
        CompletableFuture<Integer> future3 = future1.thenCombine(future2, (x, y) -> {
    
    
            Integer sum = x + y;
            System.out.println("进行合并处理:" + sum);
            return sum;
        });
        System.out.println("最终处理结果信息:"+future3.get());

  • Salida del registro:
    Insertar descripción de la imagen aquí

2.4 Comparación de tareas (applyToEither | AcceptEither | runAfterEither)

aplicar a cualquiera

applyToEither: Se utiliza principalmente para comparación y procesamiento. Cualquier tarea que se ejecute primero utilizará el resultado de cualquier tarea que se procese.
Escenario : Supongamos que necesitamos obtener datos de dos servidores remotos diferentes, o usar dos protocolos de comunicación (SSH, HTTP) para obtener datos, podemos seleccionar de forma asincrónica el applyToEithermétodo más rápido para obtener los resultados para su procesamiento.

  • Código:
        int i= 250;
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
    
    
            int number = new Random().nextInt(5);
            try {
    
    
                TimeUnit.SECONDS.sleep(number);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("使用银河计算机计算结果为:" + i+",耗时:"+number+"秒");
            return number;
        });

        CompletableFuture<Integer> future2 =CompletableFuture.supplyAsync(()->{
    
    
            int number = new Random().nextInt(5);
            try {
    
    
                TimeUnit.SECONDS.sleep(number);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("使用长城计算机计算结果为:" + i+",耗时:"+number+"秒");
            return number;
        });
		//applyToEither会得到最先执行完成的结果,进行处理,并返回一个新的结果
        CompletableFuture<String> future3 = future1.applyToEither(future2, (x) -> {
    
    
            System.out.println("结果计算成功" );
            return "最终结果执行耗时:"+x ;
        });

        System.out.println(future3.join());
        try {
    
    
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
  • Salida del registro:
    Insertar descripción de la imagen aquí

aceptarCualquiera

acceptEitherAsync: applyToEitherMismo significado y uso, excepto aceptarO consumirá directamente los resultados de las tareas anteriores sin devolver un valor
Escenario: adecuado para realizar algunos efectos secundarios cuando se completa una de las dos operaciones asincrónicas.

  • Código:
        int i= 10;
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    
    
            int number = new Random().nextInt(5);
            try {
    
    
                TimeUnit.SECONDS.sleep(number);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("使用银河计算机计算结果为:" + i+",耗时:"+number+"秒");
            return "银河计算机";
        });

        CompletableFuture<String> future2 =CompletableFuture.supplyAsync(()->{
    
    
            int number = new Random().nextInt(5);
            try {
    
    
                TimeUnit.SECONDS.sleep(number);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("使用长城计算机计算结果为:" + i+",耗时:"+number+"秒");
            return "长城计算机";
        });

//        acceptEitherAsync:和applyToEither意思和使用都一样,只不过acceptEither会把前置任务的结果直接消费掉,不会有返回值
        future1.acceptEitherAsync(future2, (x) -> {
    
    
            System.out.println("最终处理结果采用:" + x);
        }).join();


        try {
    
    
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
  • Salida del registro:
    Insertar descripción de la imagen aquí

ejecutar después de cualquiera

runAfterEither:Igual que las dos anteriores, se comparan dos tareas previas para ver cuál se ejecuta primero y luego se continúa con el siguiente paso, pero no le importarán runAfterEitherlos resultados del procesamiento de las tareas previas (sin parámetros de entrada), y allí No hay ningún valor de retorno
adecuado para su uso en Realiza alguna operación que no depende del resultado después de que se completa una de las dos operaciones asincrónicas.

  • Código:
        int i= 10;
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
    
    
            int number = new Random().nextInt(5);
            try {
    
    
                TimeUnit.SECONDS.sleep(number);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("通过http传输数据:" + i+",耗时:"+number+"秒");
            return number;
        });


        CompletableFuture<Integer> future2 =CompletableFuture.supplyAsync(()->{
    
    
            int number = new Random().nextInt(5);
            try {
    
    
                TimeUnit.SECONDS.sleep(number);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("通过web socket传输数据:" + i+",耗时:"+number+"秒");
            return number;
        });
		//没有参数也没有返回值
        future1.runAfterEither(future2,()->{
    
    
            System.out.println("任务传输成功!");
        }).join();
  • Salida del registro:
    Insertar descripción de la imagen aquí

2.4 Tareas de procesamiento por lotes (allOf | anyOf)

todo de

allOfSin valor de retorno, recibe una matriz de objetos de tareas futuras como parámetros y devuelve uno nuevo CompletableFuture. Este nuevo no se completará hasta que se hayan completado
CompletableFuture<Void>todos los objetos pasados ​​y no habrá valor de retorno. Escenario : ejecutar un conjunto de tareas asincrónicas independientes en paralelo y pasar a la siguiente operación una vez completadas todas las tareas; esperar a que se completen varias operaciones asincrónicas antes de realizar algún tipo de operación de agregación, etc.CompletableFuture

-Código:

        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    
    
            int number = new Random().nextInt(5);
            try {
    
    
                TimeUnit.SECONDS.sleep(number);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println(i+"写入mysql成功,耗时:"+number);
            return "mysql";
        });

        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
    
    
            int number = new Random().nextInt(5);
            try {
    
    
                TimeUnit.SECONDS.sleep(number);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println(i+"写入sqlserver成功,耗时:"+number);

        });
        CompletableFuture.allOf(future1, future2).join();
        System.out.println("写入数据库成功,执行后续。。。。");
  • Salida del registro:
    Insertar descripción de la imagen aquí

cualquiera de

anyOfEs CompletableFutureun método estático, utilizado principalmente para recibir múltiples tareas futuras y luego seleccionar el resultado de la primera tarea ejecutada para su uso; Es anyOfun método estático y puede recibir múltiples tareas futuras;
Escenario : También es aplicable cuando se realizan múltiples tareas ejecutado simultáneamente. Un escenario en el que se selecciona el resultado más rápido para tareas independientes; o un escenario de tiempo de espera, que se utiliza cuando se desea completar cualquiera de varias tareas dentro de un período de tiempo y realizar algunas operaciones específicas cuando se produce un tiempo de espera.

  • Código:
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    
    
            int number = new Random().nextInt(5);
            try {
    
    
                TimeUnit.SECONDS.sleep(number);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("乌龟到达终点,耗时:"+number+"秒");
            return "乌龟";
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    
    
            int number = new Random().nextInt(5);
            try {
    
    
                TimeUnit.SECONDS.sleep(number);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("兔子到达终点,耗时:"+number+"秒");
            return "兔子";
        });
        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
    
    
            int number = new Random().nextInt(5);
            try {
    
    
                TimeUnit.SECONDS.sleep(number);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("蜗牛到达终点,耗时:"+number+"秒");
            return "蜗牛";
        });
        
        CompletableFuture<Object> result = CompletableFuture.anyOf(future1, future2 ,future3);
        System.out.println("获得第一名是:"+result.join());

        try {
    
    
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

  • Salida del registro:
    Insertar descripción de la imagen aquí
    parte de la introducción está citada de https://blog.csdn.net/sermonlizhi/article/details/

Supongo que te gusta

Origin blog.csdn.net/weixin_52315708/article/details/132665368
Recomendado
Clasificación