Java中的异步和线程池

467 阅读10分钟

一、异步

1、初始化线程的四种方式

1.1、继承Thread

public class ThreadTest {
    public static void main(String[] args) {
        new Thread01().start();
   }
    
   public static class Thread01 extends Thread {
       @Override
       public void run() {
           System.err.println("start......Thread01...");
       }
   }

}

1.2、实现Runnable接口

public class ThreadTest {
    public static void main(String[] args) {
        new Thread(new Runnable01()).start();
      
   }
    
   public static class Runnable01 implements Runnable {

        @Override
        public void run() {
            System.err.println("start........Runnable01.");
        }
    }

}

1.3、实现Callable + FutureTask(可以获得返回值,可以处理异常 )

public class ThreadTest {
    public static void main(String[] args) {
         FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
        new Thread(futureTask).start();
        //阻塞等待
        Integer integer = futureTask.get();
        System.err.println(integer);
   }
    
  public static class Callable01 implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            System.err.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            return i;
        }
    }
}

1.4、线程池

public class ThreadTest {
    
     static ExecutorService service = Executors.newFixedThreadPool(10);
    
    
    public static void main(String[] args) {
           service.execute(new Runnable01());
   }
    public static class Callable01 implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            System.err.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            return i;
        }
    }
}

区别:
1、2 不能得到返回值,3可以得到返回值
1、2、3 都不能控制资源
4 可以控制资源,性能稳定

2、线程池详解

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

七大参数:

  • corePoolSize: [5] 核心线程数;线程池,创建好以后就准备就绪的线程数量,就等待来就收异步任务去执行 5个 Thread thread=new Thread(); thread.start();
  • maximumPoolSize:[200] 最大线程数;控制资源
  • keepAliveTime: 存活时间。如果当前的线程数量大于核心数量 释放空闲的线程数(maximumPoolSize- corePoolSize)。只要线程空闲大于指定的keepAliveTime
  • TimeUnit:时间单位
  • BlockingQueue workQueue: 阻塞对列。如果任务有很多,就会将目前多的任务放到队列里面。 只要有线程空闲,就回去队列里面取出新的任务去执行**
  • threadFactory: 线程创建工厂
  • RejectedExecutionHandler handler:如果队列满了,按照我们指定的拒绝策略拒绝执行任务
   public ThreadPoolExecutor(5,
                              200,
                              10,
                              TimeUnit.SECONDS,
                              new LinkBlockingQueue<>(100000),
                              Executors.DefaultThreadFactory,
                              ThreadPoolExecutor.AbortPolicy())

执行顺序

线程池创建, 准备好core数量的核心线程,准备接受任务

  • core 满了 ,  就将再进来的任务放到阻塞队列中, 空闲的core就会自己去阻塞队列中获取任务执行
  • 阻塞队列满,就直接开新线程去执行,最大只能开到max指定的数量
  • max满了就用RejectedExecutionHandler拒接任务 `
  • max都执行完成,有很多空闲,在指定的实践keepAliveTime以后,释放max-core这些线程
  • new LinkedBlockingQueue()  默认为Integer最大值 , 可能造成系统内存不足

如果队列满 所使用的的  拒绝策略:

DiscardOldestPolicy  : 放弃 最老的 任务    
DiscardPolicy : 丢弃任务 , 不跑异常      
AbortPolicy: 直接丢弃任务 , 抛异常 (默认)      
CallerRunsPolicy : 以同步的方式执行 , 直接调用 run 方法

问题:一个线程池,core=7 max=20 queue=50 100个线程如何分配

  7个线程直接运行 , 50 个进入队列 13 个 创建新的线程, 30个靠拒绝策略
 如果不想抛弃还可以使用CallerRunsPolicy以同步的方式执行 , 直接调用 run 方法

3、常见的4种线程池

1、CachedThreadPool 自动扩展的 core是0,所有都可回收

2、FixedThreadPool 固定大小的 core=max 都不可回收

3、ScheduledThreadPool 定时任务的线程池

4、SingleThreadExecutor 单个线程的线程池 后台从队列获取任务按个执行

为何使用线程池

  • 降低资源的消耗
    通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗
  • 提高响应速度
    因为线程她中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行
  • 提高线程的可管理性
    线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销。无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使用程池进行统—分配

二、CompletableFuture 异步编排

1、创建异步对象

Future 可以获取异步结果

//无返回值
public static CompletableFuture<Void> runAsync(Runnable runnable) // 
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) // 指定线程池
//有返回值
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

测试启动

public class CompletableFutureTest {
    static ExecutorService service = Executors.newFixedThreadPool(10);
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.err.println("main...........start..........");
        //---------------runAsync------------无返回值------------
//        CompletableFuture.runAsync(() -> {
//            System.err.println("当前线程:" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.err.println("运行结果:" + Thread.currentThread().getId() + i);
//        }, service);

        //---------------supplyAsync---------有返回值---------------
        CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> {
            System.err.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.err.println("运行结果:" + i);
            return i;
        }, service);
        Integer result = supplyAsync.get();
        System.err.println(result);
        System.err.println("main...........end..........");
    }
}

2、计算完成时回调方法

public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action) 
public CompletableFuture<T> whenCompleteAsync( BiConsumer<? super T, ? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor) // 能感知到异常,但是不能返回异常结果

public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn) // 感知异常 返回默认值
  • whenComplete 可以处理正常和异常的计算结果 ,exceptionally 处理异常情况
  • whenComplete , whenCompleteAsync 的区别
    whenComplete 执行当前任务的的线程继续执行whenComplete的任务  
    whenCompleteAsync 是执行把whenCompleteAsync 这个任务继续提交给线程池来执行
    方法不以 Async 结尾,意味着Action使用相同的线程执行 , 而Async 可能会使用其他线程执行(如果使用相同的线程池,也肯能被同一个线程选中执行)  
    
public class CompletableFutureTest {

    static ExecutorService service = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.err.println("main...........start..........");

        CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> {
            System.err.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 0;
            System.err.println("运行结果:" + i);
            return i;
        }, service).whenComplete((result, exception) -> {
            //虽然得到异步信息,但是没法返回数据
            System.err.println("异步任务成功完成....结果是:" + result + "异常是:" + exception);
        }).exceptionally((throwable)->{
            //可以感知异常,同时返回默认值
            return 10;
        });
        Integer result = supplyAsync.get();
        System.err.println(result);
        System.err.println("main...........end..........");
    }
}

3、handle 执行完后的处理

方法:

public <U> CompletableFuture<U> handle( BiFunction<? super T, Throwable, ? extends U> fn)
public <U> CompletableFuture<U> handleAsync( BiFunction<? super T, Throwable, ? extends U> fn)
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor)

使用:

 CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> {
            System.err.println("当前线程:" + Thread.currentThread().getId());
            int i = 100 / 5;
            System.err.println("运行结果:" + i);
            return i;
        }, service).handle((result,throwable)->{
            //方法执行完后的处理
            if(result!=null){
                return result*2;
            }
            if(throwable!=null){
                return 10;
            }
            return 0;
 });

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)
    
// 只要上面的任务执行完成, 就开始执行thenRun,只是处理任务后,执行thenRun的后续操作
public CompletableFuture<Void> thenRun(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action) 
public CompletableFuture<Void> thenRunAsync(Runnable action,Executor executor)

使用:

CompletableFuture<Void> supplyAsync = CompletableFuture.supplyAsync(() -> {
    System.err.println("当前线程:" + Thread.currentThread().getId());
    int i = 100 / 5;
    System.err.println("运行结果:" + i);
    return i;
}, service).thenRunAsync(()->{
    System.err.println("任务二启动了.....");
},service);
System.err.println("main...........end..........");

thenRun : 不能获取上一部的执行结果 无返回值

  CompletableFuture<Void> supplyAsync = CompletableFuture.supplyAsync(() -> {
            System.err.println("当前线程:" + Thread.currentThread().getId());
            int i = 100 / 5;
            System.err.println("运行结果:" + i);
            return i;
        }, service).thenAcceptAsync((res)->{
            System.err.println(res);
            System.err.println("任务二启动了.....");
        },service);
        System.err.println("main...........end..........");

thenAcceptAsync: 能接受到上一步的结果 ,无返回值

 CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> {
            System.err.println("当前线程:" + Thread.currentThread().getId());
            int i = 100 / 5;
            System.err.println("运行结果:" + i);
            return i;
        }, service).thenApplyAsync((res)->{
            System.err.println(res);
            System.err.println("任务二启动了.....");
            return res;
        },service);
        Integer integer = supplyAsync.get();
        System.err.println("main...........end.........."+integer);

thenApplyAsync 能接受上一步的结果,有返回值 对应Async默认是异步执行的,同之前。

5、两任务组合-都要完成

方法:

// 拿到前面的任务结果, 返回自己的 结果
public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn) 
public <U,V> CompletableFuture<V> thenCombineAsync( CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn)
public <U,V> CompletableFuture<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)
// 不能获取 future 结果 , 两个任务完成后触发
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)

列子:

CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
    System.err.println("任务1线程:" + Thread.currentThread().getId());
    int i = 100 / 5;
    System.err.println("任务1结果:" + i);
    return i;
}, service);
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
    System.err.println("任务2线程:" + Thread.currentThread().getId());
    System.err.println("任务2结束");
    return "Hello";
}, service);


CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {
    return f1 + ":" + f2 + "--> haha";
}, service);
System.err.println(future.get());

System.err.println("main...........end..........");

结论: thenCombine : 组合两个future,获取两个future的返回结果,并返回当前任务的返回值

        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.err.println("任务1线程:" + Thread.currentThread().getId());
            int i = 100 / 5;
            System.err.println("任务1结果:" + i);
            return i;
        }, service);
        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.err.println("任务2线程:" + Thread.currentThread().getId());
            System.err.println("任务2结束");
            return "Hello";
        }, service);

        future01.thenAcceptBothAsync(future02,(f1,f2)->{
            System.err.println("任务3线程开始:" + Thread.currentThread().getId());
            System.err.println("f1====>"+f1+",f3===>"+f2);
        },service);

        System.err.println("main...........end..........");

结论: thenAcceptBoth : 组合两个future,获取两个future任务的返回结果,然后处理任务,没有返回值。


        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.err.println("任务1线程:" + Thread.currentThread().getId());
            int i = 100 / 5;
            System.err.println("任务1结果:" + i);
            return i;
        }, service);
        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.err.println("任务2线程:" + Thread.currentThread().getId());
            System.err.println("任务2结束");
            return "Hello";
        }, service);

        future01.runAfterBothAsync(future02,()->{
            System.err.println("任务3线程:" + Thread.currentThread().getId());
            System.err.println("任务3结果:");
        },service);


        System.err.println("main...........end..........");

结论: runAfterBoth : 组合两个future,不需要获取future的结果,只需两个future处理完任务后,处理该任务。

6、两任务组合-一个完成

方法:

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) 
  
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 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) 

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

    CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
        System.err.println("任务1线程:" + Thread.currentThread().getId());
        int i = 100 / 5;
        System.err.println("任务1结果:" + i);
        return i;
    }, service);
    CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
        System.err.println("任务2线程:" + Thread.currentThread().getId());

        try {
            Thread.sleep(3000);
            System.err.println("任务2结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Hello";
    }, service);

    CompletableFuture<String> apply = future01.applyToEitherAsync(future02, res -> res.toString() + "哈哈", service);
    System.err.println(apply.get());


    System.err.println("main...........end..........");

结论: applyToEither : 两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值。

        CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
            System.err.println("任务1线程:" + Thread.currentThread().getId());
            int i = 100 / 5;
            System.err.println("任务1结果:" + i);
            return i;
        }, service);
        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
            System.err.println("任务2线程:" + Thread.currentThread().getId());

            try {
                Thread.sleep(3000);
                System.err.println("任务2结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Hello";
        }, service);

		//acceptEitherAsync没有返回结果
        future01.acceptEitherAsync(future02,(res)->{
            System.err.println("任务3开始..........之前的结果:"+res);
        },service);

结论: acceptEither : 两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。

      CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.err.println("任务1线程:" + Thread.currentThread().getId());
            int i = 100 / 5;
            System.err.println("任务1结果:" + i);
            return i;
        }, service);
        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.err.println("任务2线程:" + Thread.currentThread().getId());

            try {
                Thread.sleep(3000);
                System.err.println("任务2结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Hello";
        }, service);

        future01.runAfterEitherAsync(future02,()->{
            System.err.println("任务3开始..........之前的结果");
        },service);

结论: runAfterither : 两个任务有一个执行完成,不需要获取future的结果,处理任务,也没有返回值。

7、多任务组合

方法:

// 全部完成
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
// 完成一个
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)

例子: 获取一个商品的图片介绍和sku

   CompletableFuture<Object> futureImg = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.err.println("商品图片");
            return "hello.jpg";
        }, service);


        CompletableFuture<Object> futureAttr = CompletableFuture.supplyAsync(() -> {
            System.err.println("商品查询");
            return "黑色+256G";
        }, service);


        CompletableFuture<Object> futureDesc = CompletableFuture.supplyAsync(() -> {
            System.err.println("商品介绍");
            return "华为";
        }, service);

        CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);


		//阻塞等待
        allOf.get();

        System.err.println(futureImg.get()+"----->"+futureAttr.get()+"......"+futureDesc.get());

        System.err.println("main...........end..........");

总结: allOf : 等待所有任务完成

  CompletableFuture<Object> futureImg = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.err.println("商品图片");
            return "hello.jpg";
        }, service);


        CompletableFuture<Object> futureAttr = CompletableFuture.supplyAsync(() -> {
            System.err.println("商品查询");
            return "黑色+256G";
        }, service);


        CompletableFuture<Object> futureDesc = CompletableFuture.supplyAsync(() -> {
            System.err.println("商品介绍");
            return "华为";
        }, service);

        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
        Object o = anyOf.get();
        System.err.println("结果:"+o);

        System.err.println("main...........end..........");

总结: anyOf : 只有一个任务完成

8、配置类


import com.xiesn.springboot.utils.Threads;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 线程池配置
 *
 **/
@Configuration
public class ThreadPoolConfig {
    // 核心线程池大小
    private int corePoolSize = 50;

    // 最大可创建的线程数
    private int maxPoolSize = 200;

    // 队列最大长度
    private int queueCapacity = 1000;

    // 线程池维护线程所允许的空闲时间
    private int keepAliveSeconds = 300;

    @Bean(name = "threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setMaxPoolSize(maxPoolSize);
        executor.setCorePoolSize(corePoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        // 线程池对拒绝任务(无线程可用)的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

    /**
     * 执行周期性或定时任务
     */
    @Bean(name = "scheduledExecutorService")
    protected ScheduledExecutorService scheduledExecutorService() {
        return new ScheduledThreadPoolExecutor(corePoolSize,
                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build()) {
            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                super.afterExecute(r, t);
                Threads.printException(r, t);
            }
        };
    }
}

任务


package com.xiesn.springboot.component;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;

import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 任务工厂
 * </p>

 */
@Component
@Slf4j
public class TaskFactory {

    /**
     * 模拟5秒的异步任务
     */
    @Async
    public Future<Boolean> asyncTask1() throws InterruptedException {
        doTask("asyncTask1", 5);
        return new AsyncResult<>(Boolean.TRUE);
    }

    /**
     * 模拟2秒的异步任务
     */
    @Async
    public Future<Boolean> asyncTask2() throws InterruptedException {
        doTask("asyncTask2", 2);
        return new AsyncResult<>(Boolean.TRUE);
    }

    /**
     * 模拟3秒的异步任务
     */
    @Async
    public Future<Boolean> asyncTask3() throws InterruptedException {
        doTask("asyncTask3", 3);
        return new AsyncResult<>(Boolean.TRUE);
    }

    /**
     * 模拟5秒的同步任务
     */
    @SneakyThrows
    public void task1() {
        doTask("task1", 5);
    }

    /**
     * 模拟2秒的同步任务
     */
    @SneakyThrows
    public void task2() {
        doTask("task2", 2);
    }

    /**
     * 模拟3秒的同步任务
     */
    @SneakyThrows
    public void task3()  {
        doTask("task3", 3);
    }

    @SneakyThrows
    private void doTask(String taskName, Integer time) {
        log.info("{}开始执行..........,当前线程名称【{}】", taskName, Thread.currentThread().getName());
        TimeUnit.SECONDS.sleep(time);
        log.info("{}执行成功,当前线程名称【{}】", taskName, Thread.currentThread().getName());
    }
}

使用:


package com.xiesn.springboot.thread;

import cn.hutool.core.date.DateUtil;
import com.xiesn.springboot.component.TaskFactory;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.test.context.junit4.SpringRunner;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.*;

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class AsyncTest {
    @Autowired
    TaskFactory taskFactory;
    @Autowired
    ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    ScheduledExecutorService scheduledExecutorService;
    /**
     * 测试异步任务
     */
    @Test
    public void asyncTaskTest() throws InterruptedException, ExecutionException {
        long start = System.currentTimeMillis();
        Future<Boolean> asyncTask1 = taskFactory.asyncTask1();
        Future<Boolean> asyncTask2 = taskFactory.asyncTask2();
        Future<Boolean> asyncTask3 = taskFactory.asyncTask3();

        // 调用 get() 阻塞主线程
        asyncTask1.get();
        asyncTask2.get();
        asyncTask3.get();
        long end = System.currentTimeMillis();

        log.info("异步任务全部执行结束,总耗时:{} 毫秒" , (end - start));
    }
    /**
     * 测试同步任务
     */
    @Test
    public void taskTest()   {
        long start = System.currentTimeMillis();
        taskFactory.task1();
        taskFactory.task2();
        taskFactory.task3();
        long end = System.currentTimeMillis();

        log.info("同步任务全部执行结束,总耗时:{} 毫秒" , (end - start));
    }

    /**
     * 测试线程池
     */
    @SneakyThrows
    @Test
    public void threadPoolTest() {
        final LocalDateTime start = LocalDateTime.now();


        System.err.println("main...........start..........");
        //---------------runAsync------------带返回值------------
        CompletableFuture<String> supplyAsync1 = CompletableFuture.supplyAsync(() -> {
            taskFactory.task1();
            return "task1";
        }, threadPoolTaskExecutor);
        System.out.println("task1:");

        //---------------runAsync------------带返回值------------
        CompletableFuture<String> supplyAsync2 = CompletableFuture.supplyAsync(() -> {
            taskFactory.task2();
            return "task2";
        }, threadPoolTaskExecutor);
        System.out.println("结果task2:");

        //---------------runAsync------------带返回值------------
        CompletableFuture<String> supplyAsync3 = CompletableFuture.supplyAsync(() -> {
            taskFactory.task3();
            return "task3";
        }, threadPoolTaskExecutor);
        System.out.println("结果task3:");


        //等待所有任务完成  //阻塞方法get()
        CompletableFuture.allOf(supplyAsync1, supplyAsync2, supplyAsync3).get();

        final LocalDateTime end = LocalDateTime.now();
        System.out.println(Duration.between(start, end).toMillis());
    }


    /**
     * 测试
     */
    @Test
    public void scheduledTest() {
        System.err.println("start....."+ DateUtil.now());
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                log.info("异步任务全部执行结束,总耗时:{} 毫秒" , DateUtil.now());
            }
        }, 1000, 1 * 60 * 1000, TimeUnit.MILLISECONDS);
        //nitialDelay – 延迟第一次执行的时间
        //period – 连续执行之间的时间段
        //unit – initialDelay 和 period 参数的时间单位
        //阻塞等待防止结束.....
        while (true){

        }
    }
}