zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Avizo
    NEWS
    HOWTO
    InstallShield 2012 Spring优惠升级到最新版本(2015.4.30之前)
    Windows系统补丁KB2962872导致InstallShield无法启动(解决方案已更新)
    HOWTO: InstallScript MSI工程取Log
    安装软件列表
    阿里云推荐码 hut29f
    ios 缺少合规证明
    ios开发错误之: Undefined symbols for architecture x86_64
  • 原文地址:https://www.cnblogs.com/curedfisher/p/13858709.html
Copyright © 2011-2022 走看看