java中Runnable、Callable、Future、RunnableFuture、CompletionStage接口区别

一、Runnable接口

它只有一个run()函数,该函数没有返回值。

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

二、Callable接口

Callable与Runnable的功能大致相似,Callable中有一个call()函数,但是call()函数有返回值

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

三、Future接口

Executor(线程池)就是Runnable和Callable的调度容器。

Future接口就是对具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果等操作

get方法会阻塞,直到任务返回结果

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

四、RunnableFuture接口

是对Runnable和Future继承的一个接口,具有了他们俩的功能

public interface RunnableFuture<V> extends Runnable, Future<V> {

    void run();
}

常用实现类:FutureTask

public class FutureTask<V> implements RunnableFuture<V>

 注意:FutureTask只能执行Callable类型的任务

FutureTask的构造函数会把Runnable类型转成Callable类型,所以FutureTask最终都是执行Callable类型的任务

 

 

 通过RunnableAdapter适配器

由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService(线程池)来执行。

并且还可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。

因此FutureTask既是Future、Runnable,又是Callable(包装Runnable得到的)。

FutureTask使用方法:

//线程池
ExecutorService executor = Executors.newSingleThreadExecutor();

//构造FutureTask
FutureTask<Integer> futureTask = new FutureTask<Integer>(
    new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            Thread.sleep(1000);
            return 12345;
        }
     });
    // 提交futureTask
    executor.submit(futureTask) ;
    System.out.println("future result from futureTask : "+futureTask.get());

五、CompletionStage接口

CompletionStage是Java8新增接口,用于异步执行中的阶段处理。

大量使用函数式编程,需要有函数式编程的功底。

public class CompletableFuture<T> implements Future<T>, CompletionStage<T>

 CompletableFuture对Future的扩展和增强。CompletableFuture实现了Future接口,并在此基础上进行了丰富的扩展,完美弥补了Future的局限性,可以轻松地组织不同任务的运行顺序、规则以及方式。

接口方法可以简单划分为三类:

1、在上一阶段执行结束之后,一阶段结果作为指定函数的参数执行函数产生新的结果,apply/combine,接口参数为Bi/Function类型

2、在上一阶段执行结束之后,一阶段结果作为指定函数的参数执行函数,accept方法,接口参数为Bi/Consumer类型

3、在上一阶段执行结束之后,不依赖一阶段执行结果,执行指定的操作,run方法,接口参数为Runnable类型

关键词:

  • apply:上阶段结果作下阶段参数继续执行并返回结果
  • accept:上阶段结果作下阶段参数继续执行不返回结果
  • run:上阶段执行完比下阶段执行
  • async:异步执行,指定或者不指定线程池
  • both:前两阶段同时执行完毕执行下一阶段
  • either:前两阶段任一执行完毕执行下一阶段
  • combine:类似apply,但下一阶段执行的必须是BiFunction
  • compose:基于上阶段的执行完状态,执行下一阶段
  • complete:基于上阶段的执行完状态和结果,消费其结果
  • handler:基于上阶段的执行完状态和结果,消费其正常或者异常结果
  • exceptionally:消费异常结果

实现类CompletableFuture

使用方法

    //线程池 
    ExecutorService executor = Executors.newCachedThreadPool();


    //使用没有指定线程池时,CompletableFuture内部使用ForkJoinPool.commonPool()
    CompletableFuture userFuture = CompletableFuture.supplyAsync(() -> {
        getRemoteUserAndFill(id, userInfo);
        return Boolean.TRUE;
    }, executor);

    CompletableFuture bonusFuture = CompletableFuture.supplyAsync(() -> {
        getRemoteBonusAndFill(id, userInfo);
        return Boolean.TRUE;
    }, executor);

    CompletableFuture growthFuture = CompletableFuture.supplyAsync(() -> {
        getRemoteGrowthAndFill(id, userInfo);
        return Boolean.TRUE;
    }, executor);
    CompletableFuture.allOf(userFuture, bonusFuture, growthFuture).join();

    userFuture.get();
    bonusFuture.get();
    growthFuture.get();

常用于接口并行计算,优化接口。

 CompletableFuture可以指定异步处理流程:

  • thenAccept()处理正常结果;

  • exceptional()处理异常结果;

  • thenApplyAsync()用于串行化另一个CompletableFuture

  • anyOf()allOf()用于并行化多个CompletableFuture

CompletableFuture执行Task的时候,是需要使用线程池还是用当前的线程去执行。这个需要根据具体的情况来定。使用的时候要尽可能的小心。

猜你喜欢

转载自blog.csdn.net/sumengnan/article/details/125441347
今日推荐