java多线程编程之Future/FutureTask和Callable

有这样一种场景,用多线程发送数据到某个服务器,须要知道各个线程是否都发送成功,等全部线程都发送完成才能继续下一轮计算和发送。若是用传统的多线程方式,就须要启动多个线程,而后在每一个线程中分别发送数据,外部经过某种方式等待各个线程所有都发送完成,再进行后面的计算等流程。这种实现方式的代码会比较臃肿,在java中提供了一种Callable+Future的方法,能够将异步的多线程调用变为同步方式。java


Callable编程

在java的多线程编程中,有Thread和Runnable两种方式来新建线程,其中Runnable封装了一个异步运行的任务,能够认为是一个没有任何参数和返回值的异步方法。Callable接口相似于Runnable,二者都是为那些其实例可能被另外一个线程执行的类设计的,不一样之处在于:服务器


Runnable不会返回结果,而且没法抛出通过检查的异常。而Callable是有返回结果而且可能抛出异常的。多线程

Runnable定义了run方法,而Callable定义了一个不带任何参数的叫作call的方法。异步

此外,Callable接口的类型参数也是返回值的类型。ide


public interface Callable {this

    /**.net

    * Computes a result, or throws an exception if unable to do so.线程

    *设计

    * @return computed result

    * @throws Exception if unable to compute a result

    */

    V call() throws Exception;

}

Future

Future表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,若有必要,计算完成前能够阻塞此方法。取消则由 cancel 方法来执行。还提供了其余方法,以肯定任务是正常完成仍是被取消了。一旦计算完成,就不能再取消计算。若是为了可取消性而使用 Future 但又不提供可用的结果,则能够声明 Future<?> 形式类型、并返回 null 做为底层任务的结果。


当使用Future对象时,你就能够启动一个计算,把计算结果给某线程,而后就去干本身的事。Future对象的全部者在结果计算好以后就能够获得它。


public interface Future {

boolean cancel(boolean mayInterruptIfRunning);

boolean isCancelled();

boolean isDone();

V get() throws InterruptedException, ExecutionException;

V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;

}

FutureTask

FutureTask包装器是一种很方便地将Callable转换为Future和Runnable的机制,它同时实现了二者的接口。例如:


Callable comput = …;

FutureTask task = new FutureTask(comput);

Thread t = new Thread(task); // it's a Runnable

t.start();

Integer result = t.get(); // it’s a Future

因此可以使用FutureTask包装Callable或Runnable对象。因为FutureTask实现了Runnable,可将 FutureTask提交给线程池的执行器类Executor执行。


使用Future+Callable+ExecutorService的例子


import java.util.ArrayList;

import java.util.List;

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;

 

public class FutureTest {

 

  public static class Task implements Callable {

    private long id;

    public Task(long id){

      this.id = id;

    }

 

    @Override

    public String call() throws Exception {

      System.out.printf("Thread#%s : in call\n", this.id);

      return this.id + "";

    }

 }

 

  public static void main(String[] args) throws InterruptedException, ExecutionException {

  List results = new ArrayList();

  ExecutorService execService = Executors.newCachedThreadPool();

    for(int i=0; i<10;i++)

      results.add(execService.submit(new Task(i)));

 

  for(Future res : results)

    System.out.println(res.get());

  }

}

可见,使用Future+Callable模式对于某些须要等待多个线程执行结果的场景很是有用,在HBase的batch操做中就使用了这种模式。

相关文章
相关标签/搜索