Callable接口和Future接口

打印 上一主题 下一主题

主题 909|帖子 909|积分 2727

Callable接口和Future接口

创建线程的方式

1.继承Thread类2.实现Runnable接口3.Callable接口4.线程池方式
Callable接口

在继承Thread类和实现Runnable接口的方式创建线程时,线程执行的run方法中,返回值是void,即无法返回线程的执行结果,为了支持该功能,java提供了Callable接口。
Callable和Runnable接口的区别


  • 1.Callable中的call()方法,可以返回值,Runnable接口中的run方法,无返回值(void)。
  • 2.call()方法可以抛出异常,run()不能抛异常。
  • 3.实现Callable接口,必须重写call()方法,run是抽象方法,抽象类可以不实现。
  • 4.不能用Callable接口的对象,直接替换Runnable接口对象,创建线程。
Future接口

当call()方法完成时,结果必须存储在主线程已知的对象中,以便主线程可以知道线程返回的结果,可以使用Future对象。将Future视为保存结果的对象-该对象,不一定会将call接口返回值,保存到主线程中,但是会持有call返回值。Future基本上是主线程可以跟踪以及其他线程的结果的一种方式。要实现此接口,必须重写5个方法。
  1. public interface Future<V> {//Future源码
  2.     /**
  3.      * Attempts to cancel execution of this task.  This attempt will
  4.      * fail if the task has already completed, has already been cancelled,
  5.      * or could not be cancelled for some other reason. If successful,
  6.      * and this task has not started when {@code cancel} is called,
  7.      * this task should never run.  If the task has already started,
  8.      * then the {@code mayInterruptIfRunning} parameter determines
  9.      * whether the thread executing this task should be interrupted in
  10.      * an attempt to stop the task.
  11.      *
  12.      * <p>After this method returns, subsequent calls to {@link #isDone} will
  13.      * always return {@code true}.  Subsequent calls to {@link #isCancelled}
  14.      * will always return {@code true} if this method returned {@code true}.
  15.      *
  16.      * @param mayInterruptIfRunning {@code true} if the thread executing this
  17.      * task should be interrupted; otherwise, in-progress tasks are allowed
  18.      * to complete
  19.      * @return {@code false} if the task could not be cancelled,
  20.      * typically because it has already completed normally;
  21.      * {@code true} otherwise
  22.      */
  23.     boolean cancel(boolean mayInterruptIfRunning);
  24.     //用于停止任务,如果未启动,将停止任务,已启动,仅在mayInterrupt为true时才会中断任务
  25.     /**
  26.      * Returns {@code true} if this task was cancelled before it completed
  27.      * normally.
  28.      *
  29.      * @return {@code true} if this task was cancelled before it completed
  30.      */
  31.     boolean isCancelled();
  32.     /**
  33.      * Returns {@code true} if this task completed.
  34.      *
  35.      * Completion may be due to normal termination, an exception, or
  36.      * cancellation -- in all of these cases, this method will return
  37.      * {@code true}.
  38.      *
  39.      * @return {@code true} if this task completed
  40.      */
  41.     boolean isDone();//判断任务是否完成,完成true,未完成false
  42.     /**
  43.      * Waits if necessary for the computation to complete, and then
  44.      * retrieves its result.
  45.      *
  46.      * @return the computed result
  47.      * @throws CancellationException if the computation was cancelled
  48.      * @throws ExecutionException if the computation threw an
  49.      * exception
  50.      * @throws InterruptedException if the current thread was interrupted
  51.      * while waiting
  52.      */
  53.     V get() throws InterruptedException, ExecutionException;//任务完成返回结果,未完成,等待完成
  54.     /**
  55.      * Waits if necessary for at most the given time for the computation
  56.      * to complete, and then retrieves its result, if available.
  57.      *
  58.      * @param timeout the maximum time to wait
  59.      * @param unit the time unit of the timeout argument
  60.      * @return the computed result
  61.      * @throws CancellationException if the computation was cancelled
  62.      * @throws ExecutionException if the computation threw an
  63.      * exception
  64.      * @throws InterruptedException if the current thread was interrupted
  65.      * while waiting
  66.      * @throws TimeoutException if the wait timed out
  67.      */
  68.     V get(long timeout, TimeUnit unit)
  69.         throws InterruptedException, ExecutionException, TimeoutException;
  70. }
复制代码
Callable和Future是分别做各自的事情,Callable和Runnable类似,因为它封装了要在另一个线程上允许的任务,而Future用于存储从另一个线程获取的结果。实际上,Future和Runnable可以一起使用。创建线程需要Runnable,为了获取结果,需要Future。
FutureTask

Java库本身提供了具体的FutureTask类,该类实现了Runnable和Future接口,并方便的将两种功能组合在一起。并且其构造函数提供了Callable来创建FutureTask对象。然后将该FutureTask对象提供给Thread的构造函数以创建Thread对象。因此,间接的使用Callable创建线程。
关于FutureTask构造函数的理解
  1. public class FutureTask<V> implements RunnableFuture<V> {//实现了RunnableFuture
  2.         //该类的构造函数有两个
  3.     public FutureTask(Callable<V> callable) {//
  4.         if (callable == null)
  5.             throw new NullPointerException();
  6.         this.callable = callable;
  7.         this.state = NEW;       // ensure visibility of callable
  8.     }
  9.     //用此方法创建的线程,最后start()调用的其实是Executors.RunnableAdapter类的call();
  10.     public FutureTask(Runnable runnable, V result) {//返回的结果,就是构造函数传入的值
  11.         this.callable = Executors.callable(runnable, result);
  12.         this.state = NEW;       // ensure visibility of callable
  13.     }
  14.     //原因如下
  15.     //使用FutureTask对象的方式,创建的Thread,在开启线程.start后,底层执行的是
  16.    //Thread的方法 start()方法会调用start0(),但是调用这个start0()(操作系统创建线程)的时机,是操作系统决定的,但是这个start0()最后会调用run()方法,此线程的执行内容就在传入的对象的run()方法中
  17.     public void run() {
  18.         if (target != null) {
  19.             target.run();
  20.             //执行到这 target就是在创建Thread时,传递的Runnable接口的子类对象,FUtureTask方式就是传入的FutureTask对象
  21.             //会执行FutureTask中的run()方法
  22.         }
  23.     }
  24.     //FutureTask的run()
  25.     public void run() {
  26.         if (state != NEW ||
  27.             !UNSAFE.compareAndSwapObject(this, runnerOffset,
  28.                                          null, Thread.currentThread()))
  29.             return;
  30.         try {
  31.             Callable<V> c = callable;//类的属性
  32.             if (c != null && state == NEW) {
  33.                 V result;
  34.                 boolean ran;
  35.                 try {
  36.                     result = c.call();
  37.                     //会执行callable的call(),callable是创建TutureTask时,根据传入的Runnable的对象封装后的一个对象
  38.                     //this.callable = Executors.callable(runnable, result);
  39.                     ran = true;
  40.                 } catch (Throwable ex) {
  41.                     result = null;
  42.                     ran = false;
  43.                     setException(ex);
  44.                 }
  45.                 if (ran)
  46.                     set(result);
  47.             }
  48.         } finally {
  49.             // runner must be non-null until state is settled to
  50.             // prevent concurrent calls to run()
  51.             runner = null;
  52.             // state must be re-read after nulling runner to prevent
  53.             // leaked interrupts
  54.             int s = state;
  55.             if (s >= INTERRUPTING)
  56.                 handlePossibleCancellationInterrupt(s);
  57.         }
  58.     }
  59.     //Executors类的callable
  60.     public static <T> Callable<T> callable(Runnable task, T result) {
  61.         if (task == null)
  62.             throw new NullPointerException();
  63.         return new RunnableAdapter<T>(task, result);
  64.     }
  65.     //最后执行到这里 Executors类的静态内部类RunnableAdapter
  66.     static final class RunnableAdapter<T> implements Callable<T> {
  67.         final Runnable task;
  68.         final T result;
  69.         RunnableAdapter(Runnable task, T result) {
  70.             this.task = task;
  71.             this.result = result;
  72.         }
  73.         public T call() {
  74.             task.run();
  75.             return result;
  76.         }
  77.     }
  78. }
  79. public interface RunnableFuture<V> extends Runnable, Future<V> {//继承了Runnable, Future<V>接口
  80.         void run();//
  81. }
复制代码
使用FutureTask类间接的用Callable接口创建线程
  1. /**
  2. * @author 长名06
  3. * @version 1.0
  4. * 演示Callable创建线程 需要使用到Runnable的实现类FutureTask类
  5. */
  6. public class CallableDemo {
  7.     public static void main(String[] args) {
  8.         FutureTask<Integer> futureTask = new FutureTask<>(() -> {
  9.             System.out.println(Thread.currentThread().getName() +  "使用Callable接口创建的线程");
  10.             return 100;
  11.         });
  12.         new Thread(futureTask,"线程1").start();
  13.     }
  14. }
复制代码
核心原理

在主线程中需要执行耗时的操作时,但不想阻塞主线程,可以把这些作业交给Future对象来做。

  • 1.主线程需要,可以通过Future对象获取后台作业的计算结果或者执行状态。
  • 2.一般FutureTask多用于耗时的计算,主线程可以在完成自己的任务后,再获取结果。
  • 3.只有执行完后,才能获取结果,否则会阻塞get()方法。
  • 4.一旦执行完后,不能重新开始或取消计算。get()只会计算一次
小结


  • 1.在主线程需要执行比较耗时的操作时,但又不想阻塞主线程,可以把这些作业交给Future对象在后台完成,当主线程将来需要时,就可以通过Future对象获得后台作业的计算结果或者执行状态。
  • 2.一般FutureTask多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。
  • 3.get()方法只能获取结果,并且只能计算完后获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或抛出异常。且只计算一次,计算完成不能重新开始或取消计算。
    只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

钜形不锈钢水箱

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表