欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

【Java并发解析】Future与Callable

程序员文章站 2022-05-10 11:30:48
文章目录Runnable与Callable接口Runnable的缺陷Callable 接口Future类Callable和Future的关系重要方法Runnable与Callable接口Runnable的缺陷不支持返回一个返回值,run方法被void的修饰无法抛出check异常,也是因为原始接口的run方法是没有抛出异常的修饰的。只能用try,catch。Callable 接口类似与Runnable,被其他线程执行的任务。需要重写call方法,并且是有返回值的。而且可以抛出异常。Futur...

Runnable与Callable接口

Runnable的缺陷

  • 不支持返回一个返回值,run方法被void的修饰。public abstract void run();
  • 无法抛出check异常,也是因为原始接口的run方法是没有抛出异常的修饰的。只能用try,catch。

Callable 接口

类似与Runnable,被其他线程执行的任务。需要重写call方法,并且是有返回值的。而且可以抛出异常。V call() throws Exception;

Future类

  • 作用:用子线程去执行,主线程不用去等待执行结束。只需要在合适的时刻去调用get方法获取结果就可以。

Callable和Future的关系

  • 可以用Future.get()来获取Callable接口返回的执行任务,
  • Futuren.isDone()来判断任务是否已经执行完成或者取消任务。
  • 如果call()方法还没执行完,调用get()方法的线程会被阻塞,直到call()方法返回结果,主线程才会恢复。
  • 可以认为Future是一个存储器,存储了call()这个任务的结果。

重要方法

  • get():任务正常完成会返回,如果没有完成会被线程会被阻塞。如果call方法抛出异常,get方法抛出的异常都会是ExecutionException,并且这异常是在get方法请求的时候才会被抛出。如果任务被取消,get方法抛出CancellationException。任务超时的话抛出TimeOutException。可以带超时的时间参数。

  • cancel(): 提前结束提交的任务。可以传入一个Boolean参数,决定要不要利用interrupt进行打断当前正在执行的任务。如果任务还没开始执行或者正在执行,会返回true;如果已经执行完毕了,返回false。

  • isDone():只是执行完毕了,未必执行成功了。

  • isCanceled():判断是否被取消了

  • 构造方法:Future<?> f = service.submit(new Task());,没有完成计算之前,f是空的。然后可以用f,get()得到返回值。这里需要注意,task是需要继承Callable<>类的,并且重写call()方法。或者调用lambda方法。

方法一:继承Callable<>类

import java.util.concurrent.*;

public class FutureTask {

    static class Task implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            Thread.sleep(2000);
            return 10;
        }
    }
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService service = Executors.newFixedThreadPool(1);
        Future<Integer> future = service.submit(new Task());
        Thread.sleep(3000);
        System.out.println(future.get());
        service.shutdown();
    }
}

方法二:lambda表达式

import java.util.concurrent.*;

public class FutureTask {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService service = Executors.newFixedThreadPool(1);
        // 使用lambda表达式
        Callable<Integer> calls = ()->{
            Thread.sleep(2000);
            return 10;
        };
        Future<Integer> future = service.submit(calls);
        Thread.sleep(3000);
        System.out.println(future.get());
        service.shutdown();
    }
}

JDK中的Future

Callable是一个接口,内置了call()方法,并且是可以抛出异常的。
Future是一个接口,内置了cancelisCancelled()get()isDone()get(long, TimeUnit)这几个方法。
RunnableFuture是一个接口,利用接口的多继承,继承了FutureRunnable这两个接口,并且有一个run方法用于完成真实的运算。
FuturnTask是一个实现类,继承了RunnableFuture接口。并且执行FT的run方法时,会调用Callable接口中的call()方法完成计算,并且存储,等到get()方法调用时返回存储的结果。

用FutureTask创建Future

FutureTask是一种包装器,可以把Callable转化为Future和Runnable,实现了两者的接口。
Fi
第一步:建立一个Callable任务,Callable<V> callable = new Callable<V>(){“重写call方法”};
第二步:生成一个FutureTask类,传入Callable类型,FutureTask<Integer> ft= new FutureTask<>(callable );
第三步:线程执行ft.run,或者向线程池中提交excutor.submit(ft)
第四步:得到返回值ft.get()

具体的实现可以参考高性能缓存。

Future的注意点

无法再次初始化,生命周期无法后退,只能在创建新的Future去完成新的任务。

本文地址:https://blog.csdn.net/zcz5566719/article/details/109632100