Java 异步实现的几种方式


1. jdk1.8之前的Future

jdk并发包里的Future代表了未来的某个结果,当我们向线程池中提交任务的时候会返回该对象,可以通过future获得执行的结果,但是jdk1.8之前的Future有点鸡肋,并不能实现真正的异步,需要阻塞的获取结果,或者不断的轮询。

通常我们希望当线程执行完一些耗时的任务后,能够自动的通知我们结果,很遗憾这在原生jdk1.8之前是不支持的,但是我们可以通过第三方的库实现真正的异步回调。

/** * jdk1.8之前的Future * @author Administrator */ public class JavaFuture { public static void main(String[] args) throws Throwable, ExecutionException { ExecutorService executor = Executors.newFixedThreadPool(1); Future<String> f = executor.submit(new Callable<String>() { @Override public String call() throws Exception { System.out.println("task started!"); longTimeMethod(); System.out.println("task finished!"); return "hello"; } }); //此处get()方法阻塞main线程 System.out.println(f.get()); System.out.println("main thread is blocked"); } } 

如果想获得耗时操作的结果,可以通过get()方法获取,但是该方法会阻塞当前线程,我们可以在做完剩下的某些工作的时候调用get()方法试图去获取结果。

也可以调用非阻塞的方法isDone来确定操作是否完成,isDone这种方式有点儿类似下面的过程:
Java 异步实现的几种方式_第1张图片

2. jdk1.8开始的Future

直到jdk1.8才算真正支持了异步操作,jdk1.8中提供了lambda表达式,使得java向函数式语言又靠近了一步。借助jdk原生的CompletableFuture可以实现异步的操作,同时结合lambada表达式大大简化了代码量。代码例子如下:

package netty_promise; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Supplier; /** * 基于jdk1.8实现任务异步处理 * @author Administrator */ public class JavaPromise { public static void main(String[] args) throws Throwable, ExecutionException { // 两个线程的线程池 ExecutorService executor = Executors.newFixedThreadPool(2); //jdk1.8之前的实现方式 CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() { @Override public String get() { System.out.println("task started!"); try { //模拟耗时操作 longTimeMethod(); } catch (InterruptedException e) { e.printStackTrace(); } return "task finished!"; } }, executor); //采用lambada的实现方式 future.thenAccept(e -> System.out.println(e + " ok")); System.out.println("main thread is running"); } } 

实现方式类似下图:
Java 异步实现的几种方式_第2张图片

3. Spring的异步方法

先把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); } 

其实Spring只不过在原生的Future中进行了一次封装,我们最终获得的还是Future实例。

 

4. Java如何将异步调用转为同步

换句话说,就是需要在异步调用过程中,持续阻塞至获得调用结果。

    • 使用wait和notify方法
    • 使用条件锁
    • Future
    • 使用CountDownLatch
    • 使用CyclicBarrier


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM