Java并发编程-Callable与Future

时间:2021-09-20 18:02:48

常见的实现多线程的方式有两种,1.继承Thread类,2.实现Runnable接口,这两种实现方式无法得到线程执行的结果.所以如果想要得到线程执行最终的结果,就可以使用Callable接口与Future接口.

Callable

Callable与Runnable两者都是接口,功能基本上相似的.都是是个任务类.

先看Runnable接口,接口里面仅有一个方法.可以看到run()方法的返回值是void类型,所以是没有返回值的.

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

Callable接口里面有一个相似的Call()方法,源码如下.可以看出Callable是支持泛型的.

public interface Callable<V> {
  V call() throws Exception;
}

Future

Future接口在java.util.concurrent包下面,可以进行正在的执行的取消,判断任务是否执行完成,以及获取线程执行结果等

源码如下:

public interface Future<V> {
  boolean cancel(boolean mayInterruptIfRunning);
  boolean isCancelled();
  boolean isDone();
  V get() throws InterruptedException, ExecutionException;
  V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}

  • cancel方法的用来进行取消任务的执行.参数mayInterruptIfRunning表示是否可以取消正在执行的任务.

(1) 任务尚未启动:不管mayInterruptIfRunning设置为false还是true,由于任务还未执行,返回值为true,并且任务永不执行.

(2)任务执行中:当mayInterruptIfRunning为false的时候,表示任务不能被取消,所以方法返回值为false.当设置为true的时候,表示任务可以取消,方法的返回值为true.

(3)任务执行完成:不管mayInterruptIfRunning设置为false还是true,由于任务已经完成,无法取消,所以方法返回值为false.

  • isCancelled()方法在任务正常完成之前取消,返回值为true.
  • isDone()方法如果任务已经完成,返回值为true.
  • V get()方法获取任务执行的结果,方法会一直阻塞,直到任务执行完成拿到返回值.
  • V get(long timeout,TimeUnit unit)方法在指定的时间内进行是否能够获取到返回值,如不能,返回为null.

Future接口无法创建对象,常见使用就是Future接口的间接实现类FutureTask<V>.

FutureTask

FutureTask<V>类实现了RunnableFuture<V>接口.如下:

public class FutureTask<V> implements RunnableFuture<V> {}

而RunnableFuture<V>接口是多继承的接口,继承了Runnable接口和Future<V>接口.

public interface RunnableFuture<V> extends Runnable, Future<V> {
  void run();
}

可知FutureTask类里面有Future接口方法的所有实现和Runnable接口的方法实现.所以作为Runnable的实现类可以被多线程执行,又可以利用Future的get()方法获取线程最终的执行结果.

FutureTask里面两个构造器.

public FutureTask(Callable<V> callable) {}
public FutureTask(Runnable runnable, V result) {}

第一个构造器,当创建一个FutureTask对象的,就执行给定的Callable,第二构造器传入Runnable,result是线程成功执行要返回的结果.不需要特定的结果,可以将result置为null.

示例

1.FutureTask+Thread/FutureTaskFutureTask+ExecutorService,FutureTask简介实现Runnable,所以可以作为Runnable被线程和线程池当做任务类来执行.

public class CallableTask implements Callable<Integer> {
  @Override
  public Integer call() throws Exception {
    System.out.println("subThread"+" is running");
    int result = 0;
    for (int i = 0; i < 10; i++) {
      result += i;
    }
    Thread.sleep(3000);
    return result;
  }
}
public class FutureDemo {
  public static void main(String[] args) {
    // 创建任务类对象
    CallableTask task = new CallableTask();
    FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
    Thread thread = new Thread(futureTask);
    thread.start();
    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println("mainThread is running");
    // 判断子线程的任务是否执行完成
    if (!futureTask.isDone()) {
      try {
        System.out.println("subThread is not finished");
        Thread.sleep(2000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    try {
      System.out.println("callableTask result:" + futureTask.get());
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

执行结果

subThread is running
mainThread is running
subThread is not finished
callableTask result:4950

2.:Future+ExecutorService;此例子是将Callable任务类CallableTask扔到线程池里面执行.

public class CallableTask implements Callable<Integer> {
  @Override
  public Integer call() throws Exception {
    System.out.println("subThread"+" is running");
    int result = 0;
    for (int i = 0; i < 10; i++) {
      result += i;
    }
    Thread.sleep(3000);
    return result;
  }
}
public class FutureDemo {
  public static void main(String[] args) {
    // 创建任务类对象
    CallableTask task = new CallableTask();
    ExecutorService service = Executors.newCachedThreadPool();
    //线程池执行Callable任务类
    Future<Integer> future = service.submit(task);
    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println("mainThread is running");
    // 判断子线程的任务是否执行完成
    if (!future.isDone()) {
      try {
        System.out.println("subThread is not finished");
        Thread.sleep(2000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    try {
      System.out.println("callableTask result:" + future.get());
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

执行结果:

subThread is running
mainThread is running
subThread is not finished
callableTask result:45

3.FutureTask的集合形式:这种与前面的单个FutureTask类似.

public class ComputeTask implements Callable<Integer> {
  private int result;
  private String name;

  public ComputeTask(int result, String name) {
    this.result = result;
    this.name = name;
  }
  @Override
  public Integer call() throws Exception {
    for (int i = 0; i < 10; i++) {
      result += i;
    }
    System.out.println("subThread-" + name + " computing task has finished");
    return result;
  }
}
public class ComputeTaskDemo {
  public static void main(String[] args) {
    // 创建一个任务的集合
    List<FutureTask<Integer>> taskList = new ArrayList<FutureTask<Integer>>();
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    for (int i = 0; i < 10; i++) {
      FutureTask<Integer> futureTask = new FutureTask<Integer>(new ComputeTask(i, "task" + i));
      // 将任务添加到集合中
      taskList.add(futureTask);
      // 将任务提交给线程
      executorService.submit(futureTask);
    }
    // 获取所有的任务的计算结果
    int totalResult = 0;
    for (FutureTask<Integer> future : taskList) {
      try {
        totalResult += future.get();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    executorService.shutdown();
    System.out.println("the final result is" + totalResult);
  }
}

执行结果是:

subThread-task0 computing task has finished
subThread-task2 computing task has finished
subThread-task3 computing task has finished
subThread-task1 computing task has finished
subThread-task5 computing task has finished
subThread-task4 computing task has finished
subThread-task6 computing task has finished
subThread-task7 computing task has finished
subThread-task8 computing task has finished
subThread-task9 computing task has finished
the final result is495

参考文章

《Java并发编程实战》

https://www.cnblogs.com/ruiati/p/6133174.html