一、前言

CompletableFuture 是由Java8引入的,这让我们编写清晰可读的异步代码变得更加容易,该类功能比Future 更加强大,在Java中CompletableFuture用于异步编程,异步通常意味着非阻塞,运行任务单独的线程,与主线程隔离。

二、简单异步任务链式调用执行

示例代码:

package com.example.tcpclientdemo.test;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author qx
 * @date 2024/7/5
 * @des
 */
public class CompletableFutureTest {
    public static void main(String[] args) {
        //自定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
        CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ",1 任务执行完成");

        }, executor).thenRun(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ",2 任务执行完成");
        });
        System.out.println("主线程:" + Thread.currentThread().getName());
        executor.shutdown();
    }
}

执行结果:

主线程:main
pool-1-thread-1,1 任务执行完成
pool-1-thread-1,2 任务执行完成

三、获取上一步任务执行结果及任务完成处理

示例代码:

package com.example.tcpclientdemo.test;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * @author qx
 * @date 2024/7/5
 * @des
 */
public class CompletableFutureTest {
    public static void main(String[] args) {
        //自定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
        CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ",1 任务执行完成");
            return "one";
        }, executor).thenApply(res -> {
            System.out.println("获取上一步任务执行结果:" + res);
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ",2 任务执行完成");
            return "two";
        }).whenComplete((res, tx) -> {
            System.out.println("获取到结果:" + res);
            if (tx != null) {
                System.err.println("发生错误:" + tx.getMessage());
            }
            executor.shutdown();
        });
        System.out.println("主线程:" + Thread.currentThread().getName());
    }
}

执行结果:

主线程:main
pool-1-thread-1,1 任务执行完成
获取上一步任务执行结果:one
pool-1-thread-1,2 任务执行完成
获取到结果:two

这里如果任务执行的时候发生了异常那么在whenComplete方法中的res 会为空,tx为发生异常的对象。没有异常时res有执行的操作,tx异常对象为空。

四、异步任务异常处理

示例代码:

package com.example.tcpclientdemo.test;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * @author qx
 * @date 2024/7/5
 * @des
 */
public class CompletableFutureTest {
    public static void main(String[] args) {
        //自定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
        CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ",1 任务执行完成");
            return "one";
        }, executor).thenApply(res -> {
            System.out.println("获取上一步任务执行结果:" + res);
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ",2 任务执行完成");
            System.out.println(1 / 0);
            return "two";
        }).exceptionally(tx -> {
            System.out.println(Thread.currentThread().getName() + ",任务执行出现异常");
            return "error";
        }).whenComplete((res, tx) -> {
            System.out.println("获取到结果:" + res);
            if (tx != null) {
                System.err.println("发生错误了:" + tx.getMessage());
            }
            executor.shutdown();
        });
        System.out.println("主线程:" + Thread.currentThread().getName());
    }
}

执行结果:

主线程:main
pool-1-thread-1,1 任务执行完成
获取上一步任务执行结果:one
pool-1-thread-1,2 任务执行完成
pool-1-thread-1,任务执行出现异常
获取到结果:error

根据执行结果当发生异常时进入exceptionally方法,最终进入whenComplete方法此时 tx异常对象是发生异常的异常对象。

五、所有任务完成才算完成任务

实例代码:

package com.example.tcpclientdemo.test;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.*;
import java.util.function.Function;

/**
 * @author qx
 * @date 2024/7/5
 * @des
 */
public class CompletableFutureTest {
    public static void main(String[] args) {
        //自定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
        CompletableFuture<String> completableFuture1 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ", calc1任务执行完成");
            return "task1";
        }, executor);
        CompletableFuture<String> completableFuture2 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ", calc2任务执行完成");
            return "task2";
        }, executor);
        CompletableFuture.allOf(completableFuture1, completableFuture2).whenComplete((res, tx) -> {
            try {
                System.out.println(completableFuture1.get());
                System.out.println(completableFuture2.get());
            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException(e);
            }
            executor.shutdown();
        });

        System.out.println("主线程:" + Thread.currentThread().getName());
    }
}

执行结果:

主线程:main
pool-1-thread-1, calc1任务执行完成
pool-1-thread-2, calc2任务执行完成
task1
task2

六、handle方法对结果处理

示例代码:

package com.example.tcpclientdemo.test;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.*;
import java.util.function.Function;

/**
 * @author qx
 * @date 2024/7/5
 * @des
 */
public class CompletableFutureTest {
    public static void main(String[] args) {
        //自定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
        CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ",1 任务执行完成!");
            return 1;
        }, executor).handle((res, tx) -> res + 1).whenComplete((res, tx) -> {
            System.out.println("获取到结果:" + res);
            if (tx != null) {
                System.err.println("发生错误了:" + tx.getMessage());
            }
            executor.shutdown();
        });

        System.out.println("主线程:" + Thread.currentThread().getName());
    }
}

执行结果:

主线程:main
pool-1-thread-1,1 任务执行完成!
获取到结果:2

七、 合并异步任务

将两个异步任务完成后合并处理

示例代码:

package com.example.tcpclientdemo.test;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.*;
import java.util.function.Function;

/**
 * @author qx
 * @date 2024/7/5
 * @des
 */
public class CompletableFutureTest {
    public static void main(String[] args) {
        //自定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
        CompletableFuture<Integer> task1 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ",1 任务执行完成");
            return 1;
        }, executor);
        CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ",2 任务执行完成");
            return 2;
        }, executor);

        task1.thenCombine(task2, (t1, t2) -> {
            System.out.println(Thread.currentThread().getName() + ",合并任务完成");
            return t1 + "," + t2;
        }).whenComplete((res, tx) -> {
            System.out.println("获取到结果:" + res);
            if (tx != null) {
                System.err.println("发生错误了:" + tx.getMessage());
            }
            executor.shutdown();
        });
        System.out.println("主线程:" + Thread.currentThread().getName());
    }
}

执行结果:

主线程:main
pool-1-thread-1,1 任务执行完成
pool-1-thread-2,2 任务执行完成
pool-1-thread-2,合并任务完成
获取到结果:1,2

八、异步任务谁快谁就进入下一步的执行

两个异步任务谁先执行完谁就继续执行后续的操作。

package com.example.tcpclientdemo.test;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.*;
import java.util.function.Function;

/**
 * @author qx
 * @date 2024/7/5
 * @des
 */
public class CompletableFutureTest {
    public static void main(String[] args) {
        //自定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
        CompletableFuture<Integer> task1 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ",1 任务执行完成");
            return 1;
        }, executor);
        CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ",2 任务执行完成");
            return 2;
        }, executor);

        task1.applyToEither(task2, res -> {
            return res;
        }).whenComplete((res, tx) -> {
            System.out.println("获取到结果:" + res);
            if (tx != null) {
                System.err.println("发生错误了:" + tx.getMessage());
            }
            executor.shutdown();
        });
        System.out.println("主线程:" + Thread.currentThread().getName());
    }
}

执行结果:

主线程:main
pool-1-thread-2,2 任务执行完成
获取到结果:2
pool-1-thread-1,1 任务执行完成

九、两个异步任务都执行完了才继续执行

只有两个任务都执行完成了后才会继续。CompletableFuture.runAfterBoth

实例代码:

package com.example.tcpclientdemo.test;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.*;
import java.util.function.Function;

/**
 * @author qx
 * @date 2024/7/5
 * @des
 */
public class CompletableFutureTest {
    public static void main(String[] args) {
        //自定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
        CompletableFuture<Integer> task1 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ",1 任务执行完成");
            return 1;
        }, executor);
        CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ",2 任务执行完成");
            return 2;
        }, executor);

        task1.runAfterBoth(task2, () -> {
            System.out.println("任务都执行完成了..");
        }).whenComplete((res, tx) -> {
            System.out.println("获取到结果:" + res);
            if (tx != null) {
                System.err.println("发生错误了:" + tx.getMessage());
            }
            executor.shutdown();
        });
        System.out.println("主线程:" + Thread.currentThread().getName());
    }
}

执行 结果:

主线程:main
pool-1-thread-2,2 任务执行完成
pool-1-thread-1,1 任务执行完成
任务都执行完成了..
获取到结果:null

十、任意一个任务执行完成就算完成

CompletableFuture.anyOf

示例代码:

package com.example.tcpclientdemo.test;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.*;
import java.util.function.Function;

/**
 * @author qx
 * @date 2024/7/5
 * @des
 */
public class CompletableFutureTest {
    public static void main(String[] args) {
        //自定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
        CompletableFuture<Integer> task1 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ",1 任务执行完成");
            return 1;
        }, executor);
        CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ",2 任务执行完成");
            return 2;
        }, executor);
        // 当任务执行发生异常后,th才不会为null
        CompletableFuture.anyOf(task1, task2).whenCompleteAsync((v, th) -> {
            System.out.println("v = " + v);
            System.out.println("th = " + th);
        }, executor);

        System.out.println("主线程:" + Thread.currentThread().getName());
    }
}

执行结果:

主线程:main
pool-1-thread-2,2 任务执行完成
v = 2
th = null
pool-1-thread-1,1 任务执行完成

十一、接收上一个任务的执行结果

实例代码:

package com.example.tcpclientdemo.test;

import java.time.Duration;
import java.time.Instant;
import java.util.Random;
import java.util.concurrent.*;
import java.util.function.Function;

/**
 * @author qx
 * @date 2024/7/5
 * @des
 */
public class CompletableFutureTest {
    public static void main(String[] args) {
        //自定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
        CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("第一个任务执行完成...");
            // System.out.println(1 / 0) ;
            return new Random().nextInt(10000);
        }, executor).thenAcceptAsync(res -> { // 接收上一个任务的执行结果
            System.out.println("任务执行结果:" + res);
            executor.shutdown();
        }, executor);

        System.out.println("主线程:" + Thread.currentThread().getName());
    }
}

执行结果:

主线程:main
第一个任务执行完成...
任务执行结果:1105