创建多线程+异步实现方式总结

一、首先分为简单实现跟线程池方式实现:
简单实现:
       1、有返回值 
                继承Thread类、实现Runnable接口
        2、无返回值
                实现Callable接口
使用线程池实现:
        1、有返回值
        2、无返回值

二、实现异步的方式
        1、异步编程之CompletableFuture
        2、Spring的@Async异步

一、简单实现

      1)继承Thread,重写run方法:

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("继承Thread,重写run方法创建线程");
    }
}
 
public class Main {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
}


//直接使用匿名内部类实现
public class Main {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                System.out.println("使用匿名内部类创建 Thread 子类对象");
            }
        };
        thread.start();
    }
}

//lambda表达式
public class Main {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
           System.out.println("使用lambda表示创建线程");
        });
        thread.start();
    }
 
}

2)实现Runnable接口,重写run方法:实现Runnable接口,需要嵌套在Thread中创建实例,然后调用start方法实现

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("实现Runnable接口,重写run方法");
    }
}
 
public class Main {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}

//使用匿名内部类实现
public class Main {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("使用匿名内部类,实例Runnable接口作为构造参数");
            }
        });
        thread.start();
    }
}

3)实现Callable接口,因为有返回值,所以需要嵌套在FutureTask类中中创建实例,然后再将FutureTask嵌套在Thread类中创建实例,然后调用start()方法,就可以FutureTask.get()方法中得到返回值。

class MyCallableTest implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        System.out.println("创建线程:" + Thread.currentThread().getName());
        return 2;
    }
}
 
public class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> task = new FutureTask<>(new MyCallableTest());
        Thread thread = new Thread(task);
        thread.start();
        System.out.println("创建线程的返回结果为:" + task.get());
    }
 
}

二、使用线程池实现

        线程池实现,需要先创建线程池:

@Configuration
public class ThreadPoolConfig {
    /** Set the ThreadPoolExecutor's core pool size. */
    private int CORE_POOL_SIZE = 5;
    /** Set the ThreadPoolExecutor's maximum pool size. */
    private int MAXIMUM_POOL_SIZE = 15;
    /** Set the capacity for the ThreadPoolExecutor's BlockingQueue. */
    private int QUEUE_CAPACITY = 1000;


    @Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(CORE_POOL_SIZE);
        // 设置最大线程数
        executor.setMaxPoolSize(MAXIMUM_POOL_SIZE);
        // 设置队列容量
        executor.setQueueCapacity(QUEUE_CAPACITY);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(1000);
        // 设置默认线程名称
        executor.setThreadNamePrefix("Test-Thread-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);

        return executor;
    }

}

主要靠的是两个方法:submit() 和 execute()方法
        execute()只能执行实现Runnable接口类型的任务;execute()没有返回值
        submit()不仅可以执实现Runnable类型接口的任务,也可以执行实现Callable接口类型的任务,submit()有在添加Callable类型任务的时候有返回值。

        1)无返回值

 public static void main(String[] args) throws ExecutionException, InterruptedException {

        /** Set the ThreadPoolExecutor's core pool size. */
         int CORE_POOL_SIZE = 5;
        /** Set the ThreadPoolExecutor's maximum pool size. */
         int MAXIMUM_POOL_SIZE = 15;
        /** Set the capacity for the ThreadPoolExecutor's BlockingQueue. */
         int QUEUE_CAPACITY = 1000;


        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(CORE_POOL_SIZE);
        // 设置最大线程数
        executor.setMaxPoolSize(MAXIMUM_POOL_SIZE);
        // 设置队列容量
        executor.setQueueCapacity(QUEUE_CAPACITY);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(1000);
        // 设置默认线程名称
        executor.setThreadNamePrefix("Test-Thread-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.initialize();
//        List<FutureTask<String>> list = new ArrayList();

        for(int i = 0;i<10;i++){
            executor.execute(new ThreadTest1()); //继承Thread
            executor.submit(new ThreadTest1()); //继承Thread
            executor.execute(new ThreadTest2());//实现Runnable
            executor.submit(new ThreadTest2());//实现Runnable

        }

        executor.shutdown();
    }

        2)有返回值

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        /** Set the ThreadPoolExecutor's core pool size. */
         int CORE_POOL_SIZE = 5;
        /** Set the ThreadPoolExecutor's maximum pool size. */
         int MAXIMUM_POOL_SIZE = 15;
        /** Set the capacity for the ThreadPoolExecutor's BlockingQueue. */
         int QUEUE_CAPACITY = 1000;


        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(CORE_POOL_SIZE);
        // 设置最大线程数
        executor.setMaxPoolSize(MAXIMUM_POOL_SIZE);
        // 设置队列容量
        executor.setQueueCapacity(QUEUE_CAPACITY);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(1000);
        // 设置默认线程名称
        executor.setThreadNamePrefix("Test-Thread-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.initialize();
        
        for(int i = 0;i<10;i++){

            Future submit = executor.submit(new ThreadTest3());
            System.out.println(submit.get());
        }

        executor.shutdown();
    }

三、异步编程之CompletableFuture

         CompletableFuture对Future进行了扩展,可以通过设置回调的方式处理计算结果,同时也支持组合操作,支持进一步的编排,同时一定程度解决了回调地狱的问题。

        1)开启异步编程

         runAsync:无入参、无返回值
         supplyAsync :无入参,可以获取返回值    

    /**
     * 定义线程池
     */
    public static ExecutorService executor = Executors.newFixedThreadPool(5);

    //supplyAsync 使用默认线程池
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务...");
            return "开启异步任务,我是返回值";
        });
    //supplyAsync 使用创建线程池
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务...");
            return "开启异步任务,我是返回值";
        },executor);

    //runAsync 使用默认线程池
    CompletableFuture<String> future = CompletableFuture.runAsync(() -> {
            System.out.println("开启异步任务...");
        });
    //runAsync 使用创建线程池
    CompletableFuture<String> future = CompletableFuture.runAsync(() -> {
            System.out.println("开启异步任务...");
        },executor);

        2)计算完成回调
        当我们想第一个异步任务执行完成后,还需要做其他的事情。我们的CompletableFuture提供了计算完成时回调方法,whenCompletewhenCompleteAsyncexceptionally等接口。
        whenComplete 可以处理正常和异常的计算结果,exceptionally: 处理异常情况
        whenCompletewhenCompleteAsync 的区别是whenComplete 是执行当前任务的线程继续执行whenComplete的任务。whenCompleteAsync 是把whenCompleteAsync的任务继续提交给线程池来进行执行。

        //whenCompleteAsync
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务...");
            int i = 10 / 2;
            return i;
        }, service).whenCompleteAsync((res, exc) -> {
            System.out.println("异步任务完成了,执行结果是:" + res + "  异常是:" + exc);
        });
        System.out.println("获取异步任务返回值:" + future.get());

        //whenCompleteAsync
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务...");
            int i = 10 / 2;
            if (i == 5) {
                throw new RuntimeException("远程服务调用失败");
            }
            return i;
        }, service).whenCompleteAsync((res, exc) -> {
            System.out.println("异步任务完成了,执行结果是:" + res + "  异常是:" + exc);
        });

注意不管是使用supplyAsync创建还是使用runAsync创建异步,我们都需要在future.get()方法才能在主程序中抛出异常,但是future.get()会阻塞主线程。并且会比如第二个线程抛出异常,也会影响后面线程返回值得获取。

例如这样:

exceptionally 可以捕获并消除异常,但是也必须在最后获取future.get()方式才有效。

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务...");
            int i = 10 / 2;
            if (i == 5) {
                throw new RuntimeException("远程服务调用失败");
            }
            return i;
        }, service).whenCompleteAsync((res, exc) -> {
            System.out.println("异步任务完成了,执行结果是:" + res + "  异常是:" + exc);
        }).exceptionally(throwable -> {
            System.out.println("进入了异常处理,捕获了" + throwable.getMessage() + "异常");
            return 5;
        });
        System.out.println("获取异步任务返回值:" + future.get());

这样处理了异常之后,如果选择不在抛出,就不会阻塞主线程展示如下:

也可以重新return ,修改异步线程得返回值..如果有异常才会重置,没异常就不会重置。

        3)handle最终处理
           实际上handle等于whenComplete + exceptionally 这两个操作,前面说whenComplete 可以感知异常,获取返回值,exceptionally可以处理异常,并修改返回值。
           handle实际上可以既捕获异常,并修改返回值。

         CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务...");
            int i = 10 / 2;
            if (i == 5) {
                throw new RuntimeException("远程服务调用失败");
            }
            return i;
        }, service).handleAsync((res, thr) -> {
            System.out.println("进入handleAsync方法");
            if (res != null) {
                return res * 2;
            }
            if (thr != null) {
                System.out.println("捕获到异常" + thr);
                return 0;
            }
            return 0;
        }, service);
        System.out.println("获取异步任务返回值:" + future.get());

        4)线程串行化
             串行化的意思就是,两个线程互相影响,第一个线程完成时才开始第二个线程

public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)

public CompletableFuture<Void> thenAccept(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor)

public CompletableFuture<Void> thenRun(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action,Executor executor)
  • thenRun方法:不能获取上一步的执行结果,并且最后无返回值。
  • thenAccept方法:接收上一步的执行结果,但是最后无返回值。
  • thenApply 方法:接收上一步的执行结果,并且最后有返回值。

        thenRun: 

        CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务...");
            int i = 10 / 2;
            return i;
        }, service).thenRun(() -> {
            System.out.println("任务2启动了...");
        });
        System.out.println("获取异步任务返回值:" + future.get());

        thenAccept:

    CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务...");
            int i = 10 / 2;
            return i;
        }, service).thenAcceptAsync((res) -> {
            System.out.println("任务2启动了... 上一步的结果是:" + res);
        }, service);
        System.out.println("获取异步任务返回值:" + future.get());

         thenApply:

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务...");
            int i = 10 / 2;
            return i;
        }, service).thenApplyAsync((res) -> {
            System.out.println("任务2启动了... 上一步的结果是:" + res);
            return res * 2;
        }, service);
        System.out.println("获取异步任务最终返回值:" + future.get());

        5)两任务组合-两个任务都完成才继续执行

public <U,V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other,
         BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,
         BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,
         BiFunction<? super T,? super U,? extends V> fn,Executor executor);         

public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action)
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action)
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action, Executor executor)


public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,Runnable action)}
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action) }
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action,
                                                     Executor executor)}
  • runAfterBoth   两个都完成才执行,不接受前两个的返回值,最后也没有返回值。
  • thenAcceptBoth  两个都完成才执行,接收前两个的返回值,但是最后没有没返回值
  • thenCombine 两个都完成才执行,接收前两个的返回值,最后有返回值

   runAfterBoth   

         CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务1...");
            int i = 10 / 2;
            return i;
        });
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务2...");
            return "hello";
        });
        future1.runAfterBoth(future2, () -> {
            System.out.println("任务3 启动了....");
        });

thenAcceptBoth 

        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务1...");
            int i = 10 / 2;
            return i;
        });
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务2...");
            return "hello";
        });
        future1.thenAcceptBoth(future2, (res1, res2) -> {
            System.out.println("任务3 启动了.... 任务1的返回值:" + res1 + " 任务2的返回值:" + res2);
        });

thenCombine:

        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务1...");
            int i = 10 / 2;
            return i;
        });
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务2...");
            return "hello";
        });
        CompletableFuture<String> stringCompletableFuture = future1.thenCombine(future2, (res1, res2) -> {
            System.out.println("任务3 启动了.... 任务1的返回值:" + res1 + " 任务2的返回值:" + res2);
            return res1 + "-->" + res2;
        });

        6)两任务组合- 只要有一个任务完成就继续执行

public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,Runnable action)
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action)
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,
                                                       Executor executor)


public CompletableFuture<Void> acceptEither(
              CompletionStage<? extends T> other, Consumer<? super T> action)
public CompletableFuture<Void> acceptEitherAsync(
              CompletionStage<? extends T> other, Consumer<? super T> action)}
public CompletableFuture<Void> acceptEitherAsync(
              CompletionStage<? extends T> other, Consumer<? super T> action,Executor executor)}

public <U> CompletableFuture<U> applyToEither(
              CompletionStage<? extends T> other, Function<? super T, U> fn)
public <U> CompletableFuture<U> applyToEitherAsync(
              CompletionStage<? extends T> other, Function<? super T, U> fn)
public <U> CompletableFuture<U> applyToEitherAsync(
        CompletionStage<? extends T> other, Function<? super T, U> fn,Executor executor)

当两个任务中,任意一个future任务完成的时候,执行任务。

  • runAfterEither 两个任务有一个执行完成就继续,不获取任一结果,最后也没有返回值。
  • acceptEither 两个任务有一个执行完成,获取先执行完的返回值,最后没有返回值。
  • applyToEither 两个任务有一个任务执行完成,获取先执行完的返回值,最后有返回值。

        runAfterEither

         CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务1...");
            int i = 10 / 2;
            return i;
        });
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("开启异步任务2...");
            return "hello";
        });
        future1.runAfterEither(future2, () -> {
            System.out.println("任务3 启动了....");
        });

        acceptEither:

         CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务1...");
            int i = 10 / 2;
            return i;
        });
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("开启异步任务2...");
            return 10;
        });
        future1.acceptEither(future2, (res) -> {
            System.out.println("任务3 启动了...., 任务结果是:" + res);
        });

        applyToEither:

     CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务1...");
            int i = 10 / 2;
            return i;
        });
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("开启异步任务2...");
            return 10;
        });
        CompletableFuture<String> stringCompletableFuture = future1.applyToEither(future2, (res) -> {
            System.out.println("任务3 启动了...., 上个任务结果是:" + res);
            return "我是任务三的返回值, 上个任务的执行结果是:" + res;
        });
        System.out.println(stringCompletableFuture.get());

        7)多任务组合
        当多个任务影响下一个线程时,需要用到一下api:

public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)
  • allOf:返回的CompletableFuture是多个任务都执行完成后才会执行,只要有一个任务执行异常,则返回的CompletableFuture执行get方法时会抛出异常,如果都是正常执行,则get返回null
  • anyOf: 返回的CompletableFuture是多个任务只要其中一个执行完成就会执行,其get返回的是已经执行完成的任务的执行结果,如果该任务执行异常,则抛出异常。

        allOf

   CompletableFuture<Double> cf = CompletableFuture.supplyAsync(()->{
            System.out.println(Thread.currentThread()+" start job1,time->"+System.currentTimeMillis());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }
            System.out.println(Thread.currentThread()+" exit job1,time->"+System.currentTimeMillis());
            return 1.2;
        });
        CompletableFuture<Double> cf2 = CompletableFuture.supplyAsync(()->{
            System.out.println(Thread.currentThread()+" start job2,time->"+System.currentTimeMillis());
            try {
                Thread.sleep(1500);
            } catch (InterruptedException e) {
            }
            System.out.println(Thread.currentThread()+" exit job2,time->"+System.currentTimeMillis());
            return 3.2;
        });
        CompletableFuture<Double> cf3 = CompletableFuture.supplyAsync(()->{
            System.out.println(Thread.currentThread()+" start job3,time->"+System.currentTimeMillis());
            try {
                Thread.sleep(1300);
            } catch (InterruptedException e) {
            }
//            throw new RuntimeException("test");
            System.out.println(Thread.currentThread()+" exit job3,time->"+System.currentTimeMillis());
            return 2.2;
        });
        //allof等待所有任务执行完成才执行cf4,如果有一个任务异常终止,则cf4.get时会抛出异常,都是正常执行,cf4.get返回null
        //anyOf是只有一个任务执行完成,无论是正常执行或者执行异常,都会执行cf4,cf4.get的结果就是已执行完成的任务的执行结果
        CompletableFuture cf4=CompletableFuture.allOf(cf,cf2,cf3).whenComplete((a,b)->{
            if(b!=null){
                System.out.println("error stack trace->");
                b.printStackTrace();
            }else{
                //拼接返回值
                Double join1 = cf.join();
                Double join2 = cf2.join();
                Double join3 = cf3.join();
                System.out.println("结果 join1、join2、join3"+join1+join2+join3);
            }
        });

        System.out.println("main thread start cf4.get(),time->"+System.currentTimeMillis());
        //等待子任务执行完成
        System.out.println("cf4 run result->"+cf4.get());
        System.out.println("main thread exit,time->"+System.currentTimeMillis());

        anyOf:

        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品图片...");
            return "图片地址";
        });
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品属性...");
            return "黑色 256G";
        });
        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品品牌...");
            return "苹果手机";
        });
        CompletableFuture<Object> objectCompletableFuture = CompletableFuture.anyOf(future1, future2, future3);
        System.out.println("第一个执行成功的数据:" + objectCompletableFuture.get());

        8) get,getNow和join方法区别        

Future.get() 和 Future.join() 是 java.util.concurrent.Future 接口提供的两个方法,用于获取异步任务的结果。它们的主要区别如下:

  • 抛出异常
    Future.get() 方法声明了throws Exception,需要手动处理可能抛出的异常
    Future.join()方法没有声明抛出异常,如果任务内部抛出异常,会包装为CompletionException(unchecked异常)并抛出。
    Future.getNow() 方法不会抛出异常,而是将异常包装在ExecutionException中,并作为结果返回。
  • 阻塞行为
    Future.get() 方法是一个阻塞方法,即调用该方法后会一直等待任务完成并返回结果,如果任务未完成,调用线程会被阻塞
    Future.join()方法也是一个阻塞方法,但它是使用ForkJoinPool线程池中的工作线程执行任务,如果调用线程是ForkJoinPool线程池中的工作线程,则不会出现阻塞,而是直接执行任务。
    Future.getNow() 方法是一个非阻塞方法,如果任务已经完成,会立即返回结果,如果任务未完成,则返回传入的默认值
  • 默认值
    Future.getNow(默认值)方法需要传入一个默认值作为参数,如果任务未完成,则返回该默认值。如果不传入默认值,则会返回null

总的来说,Future.get()方法在获取异步任务结果时更具灵活性,因为它可以抛出异常且可以手动处理,但它会阻塞调用线程。而 Future.join() 方法更适用于使用 ForkJoinPool 线程池执行任务的情况,它更方便使用且不会阻塞 ForkJoinPool 线程池中的工作线程

四、Spring的@Async异步        

在@Async注解之前,使用多线程需要使用JDK的原生方法,非常麻烦,当有了@Async之后就比较简单了。

1)首先,使用 @EnableAsync 启用异步注解,在启动类上加上该注解:

@SpringBootApplication
@EnableAsync
public class StartApplication {

    public static void main(String[] args) {
        SpringApplication.run(StartApplication.class, args);
    }
}


2)自定义线程池:见上


3)在异步处理的方法上添加注解 @Async ,当对 execute 方法 调用时,通过自定义的线程池 defaultThreadPoolExecutor 异步化执行  execute 方法

@Service
public class AsyncServiceImpl implements AsyncService {
 
    @Async("defaultThreadPoolExecutor")
    public Boolean execute(Integer num) {
        System.out.println("线程:" + Thread.currentThread().getName() + " , 任务:" + num);
        return true;
    }
 
}


用 @Async 注解标记的方法,称为异步方法。在spring boot应用中使用 @Async 很简单:

1、调用异步方法类上或者启动类加上注解 @EnableAsync
2、在需要被异步调用的方法外加上 @Async
3、所使用的 @Async 注解方法的类对象应该是Spring容器管理的bean对象;
注意:
1、在类中调用 本类中被@Async 修饰的方法就不会被异步执行, 所以 @Async 方法尽量放在单独的类中,而不要挤在 冗余的代码中。
2、@Async方法默认不会继承父方法的事务。如果需要事务支持,请确保异步方法和调用该方法的方法都被@Transactional注解标记。
3、异步方法中抛出的异常不能直接捕获,因为调用者将无法获取到异常。建议使用FutureCompletableFuture来捕获异步方法的异常并进行处理。
4、异步方法默认情况下是没有返回值的,如果需要获取异步方法的执行结果,依然要使用FutureCompletableFuture,可以将其设置为返回类型。

未完还需总结:
        1、Spring ApplicationEvent事件实现异步
        2、消息队列
        3、ThreadUtil异步工具类
        4、Guava异步

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值