项目中有时会遇到一些计算耗时的模块,但是我们又不想阻塞主流程,只希望这些耗时模块自己在主流程之外默默计算,或在计算运行完之后告诉我们结果就好了。这种情况下使用异步方法调用是非常适宜的。这里介绍几种常用的异步方法的使用案例;
1、Future方法
JDK并发包里的Future代表了未来的某个结果,当我们向线程池中提交任务的时候会返回该对象,可以通过future的get()方法获得执行的结果,但是jdk1.8之前的Future有点鸡肋,并不能实现真正的异步,需要阻塞的获取结果,或者不断的轮询。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public class FutureAysnTask {
public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(2); Future<String> futureTask = executor.submit(new Callable<String>() { @Override public String call() throws Exception { System.out.println("Future task start"); String value = longTimeTask(); System.out.println("Future task end"); return value; } });
try { String value = futureTask.get(4000, TimeUnit.MILLISECONDS); System.out.println("Future task " + value); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); }
}
public static String longTimeTask() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } return "future task finish"; } }
|
- future的get()方法在获取线程执行结果时会阻塞当前线程,因此最好等到线程执行完毕之后再调用该方法。
- isDone()方法是非阻塞的,可以用来判断线程是否执行完毕。该方法类似轮询;
2、CompletableFuture方法
JDK1.8之后借助原生的CompletableFuture方法,以及lambda表达式,实现了真正的异步操作,同时也极大的简化代码逻辑;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class ComplatableFutureAsynTask {
public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(2);
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(new Supplier<String>() { @Override public String get() { System.out.println("CompletableFuture task start");
try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }
return "CompletableFuture task finished"; } }, executor); completableFuture.thenAccept(x -> { System.out.println(x); }); } }
|
3、Spring的@Aysn注解方法
使用Spring中的@Async注解,使用该注解的方法,称之为异步方法。该方法在执行的时候,会放到一个专门的线程中执行,调用者无需等待该方法执行完毕,即可做其他任务;
1 2 3 4 5 6 7 8 9 10 11 12
| @Service public class AysnChronousService { @Async public Future longTimeTask() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } return new AsyncResult( "AsynChronous task finished"); } }
|
该方法必须在其他类中使用,若在本类中的其他方法上使用则不会生效。