参考:https://www.liaoxuefeng.com/wiki/1252599548343744/1306581182447650

一.利用多线程

直接new线程

Thread t = new Thread(){
  @Override
  public void run() {
    longTimeMethod();
  }
};

 

使用线程池

private ExecutorService executor = Executors.newCachedThreadPool() ;
 
    public void fun() throws Exception {
 
        executor.submit(new Runnable(){
 
            @override
 
                public void run() {
 
                    try {
                     //要执行的业务代码,我们这里没有写方法,可以让线程休息几秒进行测试
 
                        Thread.sleep(10000);
 
                        System.out.print("睡够啦~");
 
                    }catch(Exception e) {
 
                        throw new RuntimeException("报错啦!!");
 
                    }
 
                }
 
        });
 
    }

 

 

二.采用Spring 的异步方法去执行(无返回值)

在启动类或者配置类加上 @EnableAsync 注解.

package me.deweixu.aysncdemo;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
 
@EnableAsync
@SpringBootApplication
public class AysncDemoApplication {
 
 public static void main(String[] args) {
  SpringApplication.run(AysncDemoApplication.class, args);
 }
}

 

 

先把longTimeMethod 封装到Spring的异步方法中,这个方法一定要写在Spring管理的类中,注意注解@Async

 

@Async注解可以用在方法上,也可以用在类上,用在类上,对类里面所有方法起作用

@Service
public class AsynchronousService{
  @Async
  public void springAsynchronousMethod(){
    longTimeMethod();
  }
}

 

其他类调用这个方法。这里注意,一定要其他的类,如果在同类中调用,是不生效的。具体原因,可以去学习一下Spring AOP的原理

 

@Autowired
private AsynchronousService asynchronousService;
 
public void useAsynchronousMethod(){
  //我们需要执行的代码1
  asynchronousService.springAsynchronousMethod();
 //我们需要执行的代码2
}

 

三.采用Spring 的异步方法+Future接收返回值

先把longTimeMethod 封装到Spring的异步方法中,这个异步方法的返回值是Future的实例。这个方法一定要写在Spring管理的类中,注意注解@Async。

@Service
public class AsynchronousService{
  @Async
  public Future springAsynchronousMethod(){
    Integer result = longTimeMethod();
    return new AsyncResult(result);
  }
}

 

其他类调用这个方法。这里注意,一定要其他的类,如果在同类中调用,是不生效的。

 

如果调用之后接收返回值,不对返回值进行操作则为异步操作,进行操作则转为同步操作,等待对返回值操作完之后,才会继续执行主进程下面的流程

@Autowired
private AsynchronousService asynchronousService;
 
public void useAsynchronousMethod(){
    Future future = asynchronousService.springAsynchronousMethod();
    future.get(1000, TimeUnit.MILLISECONDS);
}

 

四.原生Future方法

//我们需要执行的代码1
Future future = longTimeMethod2();
//我们需要执行的代码2
Integer result = future.get();

 

可以看到,我们调用longTimeMethod2返回一个Future对象(注意了,这里的longTimeMethod2当然不是上面的longTimeMethod),然后处理“我们需要执行的代码2”,到了需要返回结果的时候直接调用future.get()便能获取到返回值。下面我们来看看longTimeMethod2如何实现。

 

private Future longTimeMethod2() {
  //创建线程池
  ExecutorService threadPool = Executors.newCachedThreadPool();
  //获取异步Future对象
  Future future = threadPool.submit(new Callable() {
    @Override
    public Integer call() throwsException {
        return longTimeMethod();
    }
  });
  return future;
}

使用Future获得异步执行结果时,要么调用阻塞方法get(),要么轮询看isDone()是否为true,这两种方法都不是很好,因为主线程也会被迫等待。

五.原生CompletableFuture方法

CompletableFuture提供了几个回调点,可以在对应点上传入方法,可以在任务成功或失败的时候得到通知,是比较优雅的异步非阻塞获取响

@Slf4j
public class Test {
    
    public static void main(String[] args) throws InterruptedException {
        Test test = new Test();
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(test::addTable);
        //任务成功会调用这个方法
        completableFuture.thenAccept((s)->{
            log.info("任务完成!拿到结果了:" + s);
        });
        //任务失败会调用这个方法
        completableFuture.exceptionally((e)->{
            log.info("出现异常,任务失败了:" + e);
            return null;
        });
        // 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:
        Thread.sleep(2000);
    }

     String addTable() {
        try {
            Thread.sleep(1000);
             int i=1/0;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("执行 addTable");
        return "addTable";
    }
    
}