Java Callable Future示例

时间:2020-02-23 14:36:24  来源:igfitidea点击:

Java Callable和Future在多线程编程中被大量使用。
在最近的几篇文章中,我们学到了很多有关Java线程的知识,但有时我们希望线程可以返回一些我们可以使用的值。
Java 5在并发包中引入了java.util.concurrent.Callable接口,该接口类似于Runnable接口,但是它可以返回任何Object并能够引发Exception。

Java可调用

Java Callable接口使用Generic定义Object的返回类型。
Executors类提供有用的方法来在线程池中执行Java Callable。
由于可调用任务并行运行,因此我们必须等待返回的Object。

Java Future

Java可调用任务返回java.util.concurrent.Future对象。
使用Java Future对象,我们可以找出Callable任务的状态并获取返回的Object。
它提供了get()方法,可以等待Callable完成,然后返回结果。

Java Future提供了cancel()方法来取消关联的Callable任务。
get()方法有一个重载版本,可以其中指定等待结果的时间,这对于避免当前线程长时间阻塞很有用。
有isDone()和isCancelled()方法来查找关联的Callable任务的当前状态。

这是一个Java Callable任务的简单示例,该示例返回一秒钟后执行该任务的线程的名称。
我们正在使用Executor框架并行执行100个任务,并使用Java Future获取已提交任务的结果。

package com.theitroad.threads;

import java.util.ArrayList;
import java.util.Date;
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 MyCallable implements Callable<String> {

  @Override
  public String call() throws Exception {
      Thread.sleep(1000);
      //return the thread name executing this callable task
      return Thread.currentThread().getName();
  }
  
  public static void main(String args[]){
      //Get ExecutorService from Executors utility class, thread pool size is 10
      ExecutorService executor = Executors.newFixedThreadPool(10);
      //create a list to hold the Future object associated with Callable
      List<Future<String>> list = new ArrayList<Future<String>>();
      //Create MyCallable instance
      Callable<String> callable = new MyCallable();
      for(int i=0; i< 100; i++){
          //submit Callable tasks to be executed by thread pool
          Future<String> future = executor.submit(callable);
          //add Future to the list, we can get return value using Future
          list.add(future);
      }
      for(Future<String> fut : list){
          try {
              //print the return value of Future, notice the output delay in console
              //because Future.get() waits for task to get completed
              System.out.println(new Date()+ "::"+fut.get());
          } catch (InterruptedException | ExecutionException e) {
              e.printStackTrace();
          }
      }
      //shut down the executor service now
      executor.shutdown();
  }

}

一旦执行完上述程序,您将注意到输出的延迟,因为java Future get()方法等待java可调用任务完成。
另请注意,只有10个线程执行这些任务。

这是上面程序输出的代码片段。

Mon Dec 31 20:40:15 PST 2012::pool-1-thread-1
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-3
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-4
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-5
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-6
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-7
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-8
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-9
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-10
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
...

提示:如果我们想重写Java Future接口的某些方法,例如,在某个默认时间后而不是无限期地等待,将get()方法重写为超时,而不是无限期地等待,在这种情况下,Java FutureTask类很方便,它是基本实现未来界面。