当前位置: 移动技术网 > IT编程>开发语言>Java > Java中的Runnable,Callable,Future,FutureTask的比较

Java中的Runnable,Callable,Future,FutureTask的比较

2019年07月22日  | 移动技术网IT编程  | 我要评论

it培训班,追客小说网,男袜品坊

java中的runnable,callable,future,futuretask的比较

java中存在runnable、callable、future、futuretask这几个与线程相关的类或者接口,在java中也是比较重要的几个概念,我们通过下面的简单示例来了解一下它们的作用于区别。

runnable

其中runnable应该是我们最熟悉的接口,它只有一个run()函数,用于将耗时操作写在其中, 该函数没有返回值 。然后使用某个线程去执行该runnable即可实现多线程,thread类在调用start()函数后就是执行的是runnable的run()函数。runnable的声明如下 :

@functionalinterface
public interface runnable {
  /**
   * when an object implementing interface <code>runnable</code> is used
   * to create a thread, starting the thread causes the object's
   * <code>run</code> method to be called in that separately executing
   * thread.
   * <p>
   * the general contract of the method <code>run</code> is that it may
   * take any action whatsoever.
   *
   * @see   java.lang.thread#run()
   */
  public abstract void run();
}

callable

callable与runnable的功能大致相似,callable中有一个call()函数,但是 call()函数有返回值 ,而runnable的run()函数不能将结果返回给客户程序。callable的声明如下 :

@functionalinterface
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;
}

可以看到,这是一个泛型接口,call()函数返回的类型就是客户程序传递进来的v类型。

future

executor就是runnable和callable的调度容器,future就是对于具体的runnable或者callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果(future简介)。future声明如下:

* @see futuretask
 * @see executor
 * @since 1.5
 * @author doug lea
 * @param <v> the result type returned by this future's {@code get} method
 */
public interface future<v> {

  /**
   * attempts to cancel execution of this task. this attempt will
   * fail if the task has already completed, has already been cancelled,
   * or could not be cancelled for some other reason. if successful,
   * and this task has not started when {@code cancel} is called,
   * this task should never run. if the task has already started,
   * then the {@code mayinterruptifrunning} parameter determines
   * whether the thread executing this task should be interrupted in
   * an attempt to stop the task.
   *
   * <p>after this method returns, subsequent calls to {@link #isdone} will
   * always return {@code true}. subsequent calls to {@link #iscancelled}
   * will always return {@code true} if this method returned {@code true}.
   *
   * @param mayinterruptifrunning {@code true} if the thread executing this
   * task should be interrupted; otherwise, in-progress tasks are allowed
   * to complete
   * @return {@code false} if the task could not be cancelled,
   * typically because it has already completed normally;
   * {@code true} otherwise
   */
  boolean cancel(boolean mayinterruptifrunning);

  /**
   * returns {@code true} if this task was cancelled before it completed
   * normally.
   *
   * @return {@code true} if this task was cancelled before it completed
   */
  boolean iscancelled();

  /**
   * returns {@code true} if this task completed.
   *
   * completion may be due to normal termination, an exception, or
   * cancellation -- in all of these cases, this method will return
   * {@code true}.
   *
   * @return {@code true} if this task completed
   */
  boolean isdone();

  /**
   * waits if necessary for the computation to complete, and then
   * retrieves its result.
   *
   * @return the computed result
   * @throws cancellationexception if the computation was cancelled
   * @throws executionexception if the computation threw an
   * exception
   * @throws interruptedexception if the current thread was interrupted
   * while waiting
   */
  v get() throws interruptedexception, executionexception;

  /**
   * waits if necessary for at most the given time for the computation
   * to complete, and then retrieves its result, if available.
   *
   * @param timeout the maximum time to wait
   * @param unit the time unit of the timeout argument
   * @return the computed result
   * @throws cancellationexception if the computation was cancelled
   * @throws executionexception if the computation threw an
   * exception
   * @throws interruptedexception if the current thread was interrupted
   * while waiting
   * @throws timeoutexception if the wait timed out
   */
  v get(long timeout, timeunit unit)
    throws interruptedexception, executionexception, timeoutexception;
}

futuretask

futuretask则是一个runnablefuture< v>,而runnablefuture实现了runnbale又实现了futrue< v>这两个接口:

public class futuretask<v> implements runnablefuture<v> {
......
}

runnablefuture


/**
 * a {@link future} that is {@link runnable}. successful execution of
 * the {@code run} method causes completion of the {@code future}
 * and allows access to its results.
 * @see futuretask
 * @see executor
 * @since 1.6
 * @author doug lea
 * @param <v> the result type returned by this future's {@code get} method
 */
public interface runnablefuture<v> extends runnable, future<v> {
  /**
   * sets this future to the result of its computation
   * unless it has been cancelled.
   */
  void run();
}

另外futuretask还可以包装runnable和callable< v>, 由构造函数注入依赖。

/**
   * creates a {@code futuretask} that will, upon running, execute the
   * given {@code callable}.
   *
   * @param callable the callable task
   * @throws nullpointerexception if the callable is null
   */
  public futuretask(callable<v> callable) {
    if (callable == null)
      throw new nullpointerexception();
    this.callable = callable;
    this.state = new;    // ensure visibility of callable
  }

  /**
   * creates a {@code futuretask} that will, upon running, execute the
   * given {@code runnable}, and arrange that {@code get} will return the
   * given result on successful completion.
   *
   * @param runnable the runnable task
   * @param result the result to return on successful completion. if
   * you don't need a particular result, consider using
   * constructions of the form:
   * {@code future<?> f = new futuretask<void>(runnable, null)}
   * @throws nullpointerexception if the runnable is null
   */
  public futuretask(runnable runnable, v result) {
    this.callable = executors.callable(runnable, result);
    this.state = new;    // ensure visibility of callable
  }

可以看到,runnable注入会被executors.callable()函数转换为callable类型,即futuretask最终都是执行callable类型的任务。该适配函数的实现如下 :

/**
   * returns a {@link callable} object that, when
   * called, runs the given task and returns the given result. this
   * can be useful when applying methods requiring a
   * {@code callable} to an otherwise resultless action.
   * @param task the task to run
   * @param result the result to return
   * @param <t> the type of the result
   * @return a callable object
   * @throws nullpointerexception if task null
   */
  public static <t> callable<t> callable(runnable task, t result) {
    if (task == null)
      throw new nullpointerexception();
    return new runnableadapter<t>(task, result);
  }

runnableadapter适配器

/**
   * a callable that runs given task and returns given result
   */
  static final class runnableadapter<t> implements callable<t> {
    final runnable task;
    final t result;
    runnableadapter(runnable task, t result) {
      this.task = task;
      this.result = result;
    }
    public t call() {
      task.run();
      return result;
    }
  }

由于futuretask实现了runnable,因此它既可以通过thread包装来直接执行,也可以提交给executeservice来执行。并且还可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。

因此futuretask既是future、runnable,又是包装了callable(如果是runnable最终也会被转换为callable ), 它是这两者的合体。

完整示例:

package com.stay4it.rx;

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;
import java.util.concurrent.futuretask;

public class futuretest {

  public static class task implements runnable {

    @override
    public void run() {
      // todo auto-generated method stub
      system.out.println("run");
    }

  }
  public static class task2 implements callable<integer> {

    @override
    public integer call() throws exception {
      system.out.println("call");
      return fibc(30);
    }

  }

   /** 
   * runnable, 无返回值 
   */ 
  public static void testrunnable(){
    executorservice executorservice = executors.newcachedthreadpool();

    future<string> future = (future<string>) executorservice.submit(new task());
    try {
      system.out.println(future.get());
    } catch (interruptedexception e) {
      // todo auto-generated catch block
      e.printstacktrace();
    } catch (executionexception e) {
      // todo auto-generated catch block
      e.printstacktrace();
    }

    executorservice.shutdown();
  }

  /** 
   * callable, 有返回值 
   */ 
  public static void testcallable(){
    executorservice executorservice = executors.newcachedthreadpool();

    future<integer> future = (future<integer>) executorservice.submit(new task2());
    try {
      system.out.println(future.get());
    } catch (interruptedexception e) {
      // todo auto-generated catch block
      e.printstacktrace();
    } catch (executionexception e) {
      // todo auto-generated catch block
      e.printstacktrace();
    }

    executorservice.shutdown();
  }

   /** 
   * futuretask则是一个runnablefuture<v>,即实现了runnbale又实现了futrue<v>这两个接口, 
   * 另外它还可以包装runnable(实际上会转换为callable)和callable 
   * <v>,所以一般来讲是一个符合体了,它可以通过thread包装来直接执行,也可以提交给executeservice来执行 
   * ,并且还可以通过v get()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。 
   */ 
  public static void testfuturetask(){
    executorservice executorservice = executors.newcachedthreadpool();
    futuretask<integer> futuretask = new futuretask<integer>(new task2());

    executorservice.submit(futuretask);
    try {
      system.out.println(futuretask.get());
    } catch (interruptedexception e) {
      // todo auto-generated catch block
      e.printstacktrace();
    } catch (executionexception e) {
      // todo auto-generated catch block
      e.printstacktrace();
    }

    executorservice.shutdown();
  }

   /** 
   * futuretask则是一个runnablefuture<v>,即实现了runnbale又实现了futrue<v>这两个接口, 
   * 另外它还可以包装runnable(实际上会转换为callable)和callable 
   * <v>,所以一般来讲是一个符合体了,它可以通过thread包装来直接执行,也可以提交给executeservice来执行 
   * ,并且还可以通过v get()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。 
   */ 
  public static void testfuturetask2(){
    executorservice executorservice = executors.newcachedthreadpool();
    futuretask<integer> futuretask = new futuretask<integer>(new runnable() {

      @override
      public void run() {
        // todo auto-generated method stub
        system.out.println("testfuturetask2 run");
      }
    },fibc(30));

    executorservice.submit(futuretask);
    try {
      system.out.println(futuretask.get());
    } catch (interruptedexception e) {
      // todo auto-generated catch block
      e.printstacktrace();
    } catch (executionexception e) {
      // todo auto-generated catch block
      e.printstacktrace();
    }

    executorservice.shutdown();
  }



  public static void main(string[] args) {

    testcallable();

  }

  /** 
   * 效率低下的斐波那契数列, 耗时的操作 
   * 
   * @param num 
   * @return 
   */ 
  static int fibc(int num) { 
    if (num == 0) { 
      return 0; 
    } 
    if (num == 1) { 
      return 1; 
    } 
    return fibc(num - 1) + fibc(num - 2); 
  } 

}

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网