zoukankan      html  css  js  c++  java
  • java并发-Callable与Future

    基本概念:

    • Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。
    • Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由 cancel 方法来执行。还提供了其他方法,以确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明 Future<?> 形式类型、并返回 null 作为底层任务的结果。
    • FutureTask 类是 Future 的一个实现,Future 可实现 Runnable,所以可通过 Executor 来执行。

    Callable

    Callable位于java.util.concurrent包下,它也是一个接口,在它里面也只声明了一个方法,只不过这个方法叫做call():

    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类型。

      那么怎么使用Callable呢?一般情况下是配合ExecutorService来使用的,在ExecutorService接口中声明了若干个submit方法的重载版本:
      
    <T> Future<T> submit(Callable<T> task) 提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。
    Future<?> submit(Runnable task) 提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
    <T> Future<T> submit(Runnable task, T result) 提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。

    Future

     Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。
    

    boolean cancel(boolean mayInterruptIfRunning) 试图取消对此任务的执行。
    V get() 如有必要,等待计算完成,然后获取其结果。
    V get(long timeout, TimeUnit unit) 如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。
    boolean isCancelled() 如果在任务正常完成前将其取消,则返回 true。
    boolean isDone() 如果任务已完成,则返回 true。

    FutureTask

    我们可以看出FutureTask实现的是:RunnableFuture

    public class FutureTask<V>
    extends Object
    implements RunnableFuture<V>
    

    我们再看RunnableFuture

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

    可以看出RunnableFuture继承了Runnable接口和Future接口,而FutureTask实现了RunnableFuture接口。所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。

    实例1:Callable+Future

    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;
    
    public class test5 {
        public static void main(String[] args) {
            ExecutorService executor = Executors.newCachedThreadPool();
            Task task = new Task();
            Future<Integer> result = executor.submit(task);
            executor.shutdown();
             
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
             
            System.out.println("主线程在执行任务");
             
            try {
                System.out.println("task运行结果"+result.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
             
            System.out.println("所有任务执行完毕");
        }
    }
    class Task implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            System.out.println("子线程在进行计算");
            Thread.sleep(3000);
            int sum = 0;
            for(int i=0;i<100;i++)
                sum +=i;
            return sum;
        }
    }
    

    实例2:Callable+FutureTask

    public class Test {
        public static void main(String[] args) {
            //第一种方式
            ExecutorService executor = Executors.newCachedThreadPool();
            Task task = new Task();
            FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
            executor.submit(futureTask);
            executor.shutdown();
             
            //第二种方式,注意这种方式和第一种方式效果是类似的,只不过一个使用的是ExecutorService,一个使用的是Thread
            /*Task task = new Task();
            FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
            Thread thread = new Thread(futureTask);
            thread.start();*/
             
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
             
            System.out.println("主线程在执行任务");
             
            try {
                System.out.println("task运行结果"+futureTask.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
             
            System.out.println("所有任务执行完毕");
        }
    }
    class Task implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            System.out.println("子线程在进行计算");
            Thread.sleep(3000);
            int sum = 0;
            for(int i=0;i<100;i++)
                sum += i;
            return sum;
        }
    }
    

    引用块内容
    http://www.cnblogs.com/dolphin0520/p/3949310.html
    java核心技术 卷I

  • 相关阅读:
    Kotlin 实现类似 C# 的 Event 事件代码
    nim 语言实现迭代器
    nim 语言使用 concept 实现 c# 的interface
    如何在 asp.net core mvc 项目中管理前端插件的引用
    遇到一个在 WPF 中使用 MessageBox 弹出但在打开后却立即自动关闭的问题
    如何在项目生成成功后,自动构建 nuget 包并复制或发布到指定位置
    在类库开发中,如何设定多个 .net 框架目标
    如何在 IIS 中重定向 http 请求至 https
    在 docker 中部署 phpmyadmin 使用 nginx 代理 https 时出现错误无法登录
    禅道中配置电子邮件发信遇到 SMTP 错误:无法连接到 SMTP 主机,点击重试可以成功
  • 原文地址:https://www.cnblogs.com/csuwater/p/5414641.html
Copyright © 2011-2022 走看看