Callable的Future模式

线程实现方式

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

无论使用继承Thread类还是实现Runnable接口,还是使用线程池都没有办法解决2个问题

1.线程执行没有返回值结果
2.线程执行没有办法抛出异常,只能自己通过try-catch解决

Callable

在java中,创建线程一般有两种方式,一种是继承Thread类,一种是实现Runnable接口。然而,这两种方式的缺点是在线程任务执行结束后,无法获取执行结果。我们一般只能采用共享变量或共享存储以及线程通信的方式实现获得任务结果的目的;  

不过,在java中,也提供了使用Callable和Future来实现获取任务结果的操作。Callable用来执行任务,产生结果,而Future用来获得结果;

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

Callable和Runnable的区别:

1.Callable能接受一个泛型,然后在call方法中返回一个这个类型的值,而Runnable的run方法没有返回值;

2.Callable的call方法可以抛出异常,而Runnable的run方法不会抛出异常;

Future模式

Future莫斯的核心在于:去除了函数的等待时间,并使得原来需要等待的时间段可以用于处理其他业务逻辑;

Future模式:对于多线程,如果线程A要等待线程B的结果,那么线程A没有必要等待线程B,知道线程B有结果,可以先拿到一个未来的Future,等线程B有结果时再取真实的结果; 

调用Callable的第一种实现方案:

public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println("Callable接口中重写的Call方法,可以有返回值并且抛出异常");
        return "callable";
    }

    //调用Callable的第一种实现方案
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCallable myCallable=new MyCallable();
        //利用FutureTask执行Callable并且接受结果
        FutureTask<String> stringFutureTask = new FutureTask<>(myCallable);
        //利用线程执行Task任务
        new Thread(stringFutureTask).start();
        //接受结果FutureTask.get会发生阻塞情况
        System.out.println(stringFutureTask.get());

        System.out.println("MyCallable执行完毕,返回值结果正确接收~");
    }
}

控制台效果

调用Callable的第二种实现方案:

public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println("Callable接口中重写的Call方法,可以有返回值并且抛出异常");
        return "callable";
    }

    //调用Callable的第二种实现方案
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        MyCallable myCallable=new MyCallable();
        //创建一个线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        //创建线程执行任务,接受任务结果
        Future<String> future = executorService.submit(myCallable);
        //接受返回值
        System.out.println(future.get(2000,TimeUnit.MILLISECONDS));
        System.out.println("方式二,线程池:MyCallable执行完毕,返回值结果正确接收~");
        //停止线程池
        executorService.shutdown();
    }
}

控制台效果

  Future常用方法

V get():获取异步执行的结果,如果没有结果可用,此方法会阻塞知道异步计算完成;

V get(Long timeout,TimeUnit unit):获取异步执行结果,如果没哟结果可用,此方法会阻塞,但是会有时间限制,如果阻塞时间超过设定的timeout时间,该方法将抛出异常;

  boolean isDone():如果任务执行结束,无论是正常结束或是中途取消还是发生异常,都返回true;

  boolean isCanceller():如果任务完成前被取消,则返回true;

  boolean cancel(boolean mayInterrupRunning):如果任务还没有开始,执行cancel方法将返回false;如果任务已经启动,执行cancel方法将以中断执行此任务线程的方式来试图停止任务,如果停止成功,返回true;

  当任务已经启动,执行cancel(false)方法将不会对正在执行的任务线程产生影响(让线程正常执行到完成),此时返回false;

  当任务已经启动,执行cancel方法将返回false,MayInterruptRunning参数表示是否中断执行中的线程;

  实际上Future提供了三种功能:

    1.能够中断执行中的任务;

    2.判断任务是否执行完成;

    3.获取任务执行完成后的结果;

原文地址:https://www.cnblogs.com/dabrk/p/12553807.html