当前位置: 首页 > news >正文

java Callable与Future

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

Future模式

Future接口是Java线程Future模式的实现,可以来进行异步计算。

Future模式可以这样来描述:

我有一个任务,提交给了Future,Future替我完成这个任务。期间我自己可以去做任何想做的事情。一段时间之后,我就便可以从Future那儿取出结果。

就相当于下了一张订货单,一段时间后可以拿着提订单来提货,这期间可以干别的任何事情。其中Future接口就是订货单,真正处理订单的是Executor类,它根据Future接口的要求来生产产品。

 

Callable和Future接口

 

Callable接口

 

Callable和Future一个产生结果,一个拿到结果。

Callable接口类似于Runnable,但是Runnable不会返回结果,而Callable可以返回结果,这个返回值可以被Future拿到,也就是说,Future可以拿到异步执行任务的返回值。

  •  V call()

 

  1. /** 
  2.  * Computes a result, or throws an exception if unable to do so. 
  3.  * 
  4.  * @return computed result 
  5.  * @throws Exception if unable to compute a result 
  6.  */  
  7. V call() throws Exception;  


 

 

Future接口

Future 表示异步计算的结果。Future接口中有如下方法:

  •     boolean cancel(boolean mayInterruptIfRunning)

取消任务的执行。参数指定是否立即中断任务执行,或者等等任务结束

  •     boolean isCancelled() 

任务是否已经取消,任务正常完成前将其取消,则返回 true

  •     boolean isDone()

任务是否已经完成。需要注意的是如果任务正常终止、异常或取消,都将返回true

  •     V get()

等待任务执行结束,然后获得V类型的结果。InterruptedException 线程被中断异常, ExecutionException任务执行异常,如果任务被取消,还会抛出CancellationException

  •     V get(long timeout, TimeUnit unit) 

同上面的get功能一样,多了设置超时时间。参数timeout指定超时时间,uint指定时间的单位,在枚举类TimeUnit中有相关的定义。如果计算超时,将抛出TimeoutException
 

Future接口提供方法来检测任务是否被执行完,等待任务执行完获得结果。也可以设置任务执行的超时时间,这个设置超时的方法就是实现Java程序执行超时的关键。

所以,如果需要设定代码执行的最长时间,即超时,可以用Java线程池ExecutorService类配合Future接口来实现。

  1. int result = future.get(5000, TimeUnit.MILLISECONDS);   


 

Future实现类:SwingWorker

 

SwingWorker的用法

http://blog.csdn.net/vking_wang/article/details/8994882 

 

 

 

Future实现类:FutureTask

 

Future的实现类有java.util.concurrent.FutureTask<V>即 javax.swing.SwingWorker<T,V>。通常使用FutureTask来处理我们的任务。

FutureTask类同时又实现了Runnable接口,所以可以直接提交给Thread、Executor执行。

public class CallableAndFuture {    
    public static void main(String[] args) {    
        Callable<Integer> callable = new Callable<Integer>() {    
            public Integer call() throws Exception {    
                return new Random().nextInt(100);    
            }    
        };   
  
        FutureTask<Integer> future = new FutureTask<Integer>(callable);    
        new Thread(future).start();    
  
        try {    
            Thread.sleep(5000);// 可能做一些事情    
  
            int result = future.get();    
  
        } catch (InterruptedException e) {    
            e.printStackTrace();    
        } catch (ExecutionException e) {    
            e.printStackTrace();    
        }    
    }    
}    

 

通过ExecutorService的submit方法执行Callable,并返回Future

 

使用ExecutorService

 

public class CallableAndFuture {    
    public static void main(String[] args) {   
  
        //ExecutorService.submit()  
        ExecutorService threadPool = Executors.newSingleThreadExecutor();    
        Future<Integer> future = threadPool.submit(new Callable<Integer>() {    
            public Integer call() throws Exception {    
                return new Random().nextInt(100);    
            }    
        });   
  
        try {    
            Thread.sleep(5000);// 可能做一些事情    
  
            int result = future.get(); //Future.get()  
  
        } catch (InterruptedException e) {    
            e.printStackTrace();    
        } catch (ExecutionException e) {    
            e.printStackTrace();    
        }    
    }    
}    

 

如果要执行多个带返回值的任务,并取得多个返回值,可用CompletionService:

CompletionService相当于Executor加上BlockingQueue,使用场景为当子线程并发了一系列的任务以后,主线程需要实时地取回子线程任务的返回值并同时顺序地处理这些返回值,谁先返回就先处理谁。

public class CallableAndFuture {    
    public static void main(String[] args) {    
        ExecutorService threadPool = Executors.newCachedThreadPool();    
        CompletionService<Integer> cs = new ExecutorCompletionService<Integer>(threadPool);    
        for(int i = 1; i < 5; i++) {    
            final int taskID = i;    
            //CompletionService.submit()  
            cs.submit(new Callable<Integer>() {    
                public Integer call() throws Exception {    
                    return taskID;    
                }    
            });    
        }    
        // 可能做一些事情    
        for(int i = 1; i < 5; i++) {    
            try {    
                int result = cs.take().get();  //CompletionService.take()返回Future  
            } catch (InterruptedException e) {    
                e.printStackTrace();    
            } catch (ExecutionException e) {    
                e.printStackTrace();    
            }    
        }    
    }    
}          

或者不使用CompletionService:先创建一个装Future类型的集合,用Executor提交的任务返回值添加到集合中,最后便利集合取出数据。如下所示:

 

class TaskWithResult implements Callable<String> {  
    private int id;  
  
    public TaskWithResult(int id) {  
        this.id = id;  
    }  
  
    @Override  
    public String call() throws Exception {  
        return "result of TaskWithResult " + id;  
    }  
}  
  
public class CallableTest {  
    public static void main(String[] args) throws InterruptedException,  
            ExecutionException {  
        ExecutorService exec = Executors.newCachedThreadPool();  
        ArrayList<Future<String>> results = new ArrayList<Future<String>>();    //Future 相当于是用来存放Executor执行的结果的一种容器  
        for (int i = 0; i < 10; i++) {  
            results.add(exec.submit(new TaskWithResult(i)));  
        }  
        for (Future<String> fs : results) {  
            if (fs.isDone()) {  
                System.out.println(fs.get());  
            } else {  
                System.out.println("Future result is not yet complete");  
            }  
        }  
        exec.shutdown();  
    }  
}

 

 

区别:

Future集合方法,submit的task不一定是按照加入自己维护的list顺序完成的。从list中遍历的每个Future对象并不一定处于完成状态,这时调用get()方法就会被阻塞住,如果系统是设计成每个线程完成后就能根据其结果继续做后面的事,这样对于处于list后面的但是先完成的线程就会增加了额外的等待时间。

而CompletionService的实现是维护一个保存Future对象的BlockingQueue。只有当这个Future对象状态是结束的时候,才会加入到这个Queue中,take()方法其实就是Producer-Consumer中的Consumer。它会从Queue中取出Future对象,如果Queue是空的,就会阻塞在那里,直到有完成的Future对象加入到Queue中。

所以,先完成的必定先被取出。这样就减少了不必要的等待时间。

参考文章:

http://www.voidcn.com/blog/vking_wang/article/p-2434628.html

转载于:https://my.oschina.net/u/1540325/blog/779157

相关文章:

  • javascipt的【函数表达式】
  • 从RethinkDB的倒闭反思开源项目可持续的盈利模式
  • 笔试网站
  • (31)对象的克隆
  • SQL优化 CREATE STATISTICS
  • quartz2的example3--CronTriggerExample
  • ubuntu 14 中tomcat的开机启动设置
  • Java豆瓣电影爬虫——抓取电影详情和电影短评数据
  • InitialContext和lookup
  • 转】Mahout分步式程序开发 聚类Kmeans
  • Python 查看QQ状态
  • 前端弹出层框架layer
  • expect的超时处理
  • 自定义QGraphicsItem
  • FZU-2087 统计树边(最小生成树)
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • 【EOS】Cleos基础
  • 2018天猫双11|这就是阿里云!不止有新技术,更有温暖的社会力量
  • avalon2.2的VM生成过程
  • ECMAScript6(0):ES6简明参考手册
  • Github访问慢解决办法
  • Java,console输出实时的转向GUI textbox
  • jquery ajax学习笔记
  • KMP算法及优化
  • leetcode-27. Remove Element
  • Vue2.x学习三:事件处理生命周期钩子
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • 悄悄地说一个bug
  • 如何合理的规划jvm性能调优
  • 小程序01:wepy框架整合iview webapp UI
  • ​sqlite3 --- SQLite 数据库 DB-API 2.0 接口模块​
  • ​草莓熊python turtle绘图代码(玫瑰花版)附源代码
  • # include “ “ 和 # include < >两者的区别
  • # 达梦数据库知识点
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • ${ }的特别功能
  • (4)事件处理——(7)简单事件(Simple events)
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (附源码)spring boot建达集团公司平台 毕业设计 141538
  • (附源码)springboot人体健康检测微信小程序 毕业设计 012142
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (图)IntelliTrace Tools 跟踪云端程序
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • .NET 4.0中的泛型协变和反变
  • .NET Core 将实体类转换为 SQL(ORM 映射)
  • .net core 依赖注入的基本用发
  • .NET/C# 避免调试器不小心提前计算本应延迟计算的值
  • .NET/C# 解压 Zip 文件时出现异常:System.IO.InvalidDataException: 找不到中央目录结尾记录。
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • .net的socket示例
  • @DataRedisTest测试redis从未如此丝滑