Guava 中的 ListenableFuture

来源:互联网 发布:剑灵数据互通查询 编辑:程序博客网 时间:2024/05/16 17:59

前几天看hdfs QJM的代码,里面看到一个ListenableFuture,说实话对于Java,目前我还只是通过看代码,遇到没见过的再去查的方式,也着实是没有时间和精力再去通篇研读诸如《thinking in Java》这样的大砖块了,现在这样的方式,目前来说应该是够用了。重点还是放在系统和业务上,语言本身本不应该成为障碍。言归正传,回到ListenableFuture, 在网上看了一下相关的资料,把它的来龙去脉了解了一下,在这里记录一下。

前面提到的ListenableFuture, 是google开源的自己的Java Library Guava(http://code.google.com/p/guava-libraries/)中的一个模块,它本身是继承是Java的Future。严格来讲,Future是一种Design Pattern, 它本身跟语言是没有关系的。最新的C++11中,也加入了Future的支持,不过笔者以前写C++的时候,C++11还没正式发布,加上它本身也是比较新的,主流的编译器支持的本身也不是很好,因此只是知道它的存在,并没有去研究过它是做什么的,怎么来使用的。接下来,我会通过一些Java的Future的例子,来一步步介绍Future及其用法。

简单来讲,Future是这样一种Pattern: 它本身表示‘将来(future)’,你提交一个异步的任务,比如提交到一个threadpool,与此同时拿到一个Future对象,任务的执行是异步的,这时候你可以去做其它的事情,等到异步任务结束的时候,你可通过前面的Future对象拿到异步执行的任务的结果。下面通过一个简单的例子来直观感受一下Future:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
 
public class FutureTest {
 
  public static void main(String[] args) {
    ExecutorService executor = Executors.newFixedThreadPool(1);
 
    Future< String> future = executor.submit(new Callable< String>() {
      public String call() {
        return "Hello futue!";
      }
    });
 
    try {
      Thread.sleep(1000);
      System.out.println(future.get());
    } catch (InterruptedException e) {
      future.cancel(true);
    } catch (ExecutionException e) {
      future.cancel(true);
    } finally {
      executor.shutdown();
    }
  }
}


在上面的程序中,和我注意到第20行的Thread.sleep(1000),这里的原本的含义是在异步任务执行期间,原线程可以做任何事情,不会阻塞。这里简单用了sleep,但要表达的意思是清楚的。

看了上面的例子,细心的朋友总会有这样的疑问,Future要获取异步任务执行的结果,需要通过轮询或者阻塞等待的方式,这样的方式,总显得不太‘完美’,我们知道,比较好的方式,应该是异步执行结束后,自动通知用户异步任务结束了,你可以通过Future来获取执行结果了。这就诞生了google的ListenableFuture,用户可以向它注册一个回调函数和提供一个线程池(可选),当异步任务执行结束后,它会自动在用户提供的线程池里调用用户注册的回调函数,通知用户异步任务执行结束了。当然,如果用户不提供线程池,它会在运行异步任务的工作线程里运行回调函数,这种情况适用于工作线程本身的任务比较轻量级的情景。下面通过几个例子,说明ListenableFuture的具体的用法:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
 
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
 
public class ListenableFutureTest {
 
  public static void main(String[] args) {
    ListeningExecutorService executor = MoreExecutors.listeningDecorator(
        Executors.newFixedThreadPool(1));
 
    final ListenableFuture< String> future = executor.submit(
        new Callable< String>() {
      public String call() throws Exception {
        return "Hello listenable future";
      }
    });
 
    future.addListener(new Runnable() {
      public void run() {
        try {
          System.out.println(future.get());
        } catch (InterruptedException e) {
          future.cancel(true);
        } catch (ExecutionException e) {
          future.cancel(true);
        }
      }
    }, Executors.newFixedThreadPool(1));
 
    System.out.println("exit..");
  }
}


上面的程序中,第35行的System.out.println(“exit..”);可能会先于“Hello listenable future” print到stdout上,这也间接能说明回调函数的执行是在别的线程中的。另外,在上面的例子中,我们发现,用户需要在注册的回调函数中处理InterruptedException和ExecutionException, 显得略为麻烦。这里Guava还提供了另为一种使用方式,接口上来看,更加清晰一些,下面是这种方式的使用的一个例子:

import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
 
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
 
public class ListenableFutureTest2 {
 
  public static void main(String[] args) {
    ListeningExecutorService executor = MoreExecutors.listeningDecorator(
        Executors.newFixedThreadPool(1));
 
    final ListenableFuture< String> future = executor.submit(
        new Callable< String>() {
      public String call() throws Exception {
        return "Hello listenable future";
      }
    });
 
    Futures.addCallback(future, new FutureCallback< String>() {
      public void onSuccess(String result) {
        System.out.println(result);
      }k
 
      public void onFailure(Throwable t) {
        System.out.println("error: " + t);
      }
 
    }, Executors.newFixedThreadPool(1));
 
    System.out.println("exit..");
  }
}


http://www.wuzesheng.com/?p=2485

0 0
原创粉丝点击