8_关于Callable, Future和FutureTask

  • 耳熟能详的两种创建线程的方式是扩展Thread和实现Runnable接口

    但是它们有一个固有缺陷: 无法获取执行的结果

    为了解决这个问题, Callable诞生了

  • Callable

    (1) 在java.util.concurrent包下, 是一个泛型接口

      public interface Callable<V> {
    
         /**
          * 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;
      }
    

    (2) 接口中只有一个call()方法, 类似于Runnable中的run()方法,但是run()方法既没有返回值也不抛出异常

      public interface Runnable {
    
           public abstract void run();
      }
    

    (3) JavaDoc中说, Executor类中提供了静态方法, 可以将普通的Runnable转换为Callable(这种适合集体转换, 例如都返回true或者都返回false)

    Executor中提供的方法

      public static <T> Callable<T> callable(Runnable task, T result);
    
      public static Callable<Object> callable(Runnable task);
    
  • Future

    (1) 是一个java.util.concurrent中的接口, 它提供了几个5个方法

      boolean cancel(boolean mayInterruptIfRunning); --取消未完成的任务
    
      boolean isCancelled(); --判断是否任务已经取消
    
      boolean isDone(); --判断任务是否完成
    
      V get() throws InterruptedException, ExecutionException; --获取任务的完成结果(获取不到就阻塞)
    
      V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;  --获取任务的完成结果,带定时
    

    (2) Future常常与线程池一起使用, 例如executor.submit(Callable task);会返回一个Future对象

  • FutureTask

    (1) FutureTask是一个java.util.concurrent中的类, 它实现了RunnableFuture接口; 而RunnableFuture接口实现了Runnable和Future接口, 所以FutureTask对象可以既可以传入Thread的构造参数中, 也可以作为Future的接口实例

    (2) FutureTask的构造函数形式有两种

      public FutureTask(Callable<V> callable);  传入一个callable对象
    
      public FutureTask(Runnable runnable, V result); 传入一个runnable对象和一个result结果用于get()
    
  • 示例

    (1) 不使用线程池

      class Example {
    
          static 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[]) {
    
              List<FutureTask<String>> taskList = new ArrayList<>();
    
              // run each task
              for (int i = 0; i < 10; i++) {
    
                  FutureTask<String> task = new FutureTask<>(new MyCallable());
                  taskList.add(task);
    
                  Thread thread = new Thread(task, String.valueOf(i));
                  thread.start();
              }
    
              // get result of myCallable.call()(but from future.get() directly);
              for (FutureTask<String> task: taskList) {
                  try {
                      System.out.println(task.get());
                  } catch (InterruptedException | ExecutionException e) {
                      e.printStackTrace();
              }
          }
      }
    

    (2) 使用线程池

      class Example {
    
          static class MyCallable implements Callable<String> {
    
              @Override
              public String call() throws Exception {
    
                  Thread.sleep(1000);
          
                  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 {
                      System.out.println(new Date() + "::" + fut.get());
                  } catch (InterruptedException | ExecutionException e) {
                      e.printStackTrace();
                  }
              }
    
              //shut down the executor service now
              executor.shutdown();
          }
      }
    

猜你喜欢

转载自blog.csdn.net/captxb/article/details/87633436