转自:https://www.jb51.net/article/240466.htm
参考: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"; } }