1.FutrueTask概念

FutureTask一个可取消的异步计算,FutureTask 实现了Future的基本方法,提空 start cancel 操作,可以查询计算是否已经完成,并且可以获取计算的结果。结果只可以在计算完成之后获取,get方法会阻塞当计算没有完成的时候,一旦计算已经完成,那么计算就不能再次启动或是取消。

一个FutureTask 可以用来包装一个 Callable 或是一个runnable对象。因为FurtureTask实现了Runnable方法,所以一个 FutureTask可以提交(submit)给一个Excutor执行(excution).

2.FutureTask使用场景

FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。另外,FutureTask还可以确保即使调用了多次run方法,它都只会执行一次Runnable或者Callable任务,或者通过cancel取消FutureTask的执行等。

2.1 FutureTask执行多任务计算场景

利用FutureTask和ExecutorService,可以用多线程的方式提交计算任务,主线程继续执行其他任务,当主线程需要子线程的计算结果时,在异步获取子线程的执行结果。

1 /**

2 * Created by zhumiao on 2018/8/17.3 */

4 public classFutureTest1 {5 public static voidmain(String[] args) {6 Task task = new Task();//新建异步任务

7 FutureTask future = new FutureTask(task) {8 //异步任务执行完成,回调

9 @Override10 protected voiddone() {11 try{12 System.out.println("future.done():" +get());13 } catch(InterruptedException e) {14 e.printStackTrace();15 } catch(ExecutionException e) {16 e.printStackTrace();17 }18 }19 };20 //创建线程池(使用了预定义的配置)

21 ExecutorService executor =Executors.newCachedThreadPool();22 executor.execute(future);23

24 try{25 Thread.sleep(1000);26 } catch(InterruptedException e1) {27 e1.printStackTrace();28 }29 //可以取消异步任务30 //future.cancel(true);

31 try{32 //阻塞,等待异步任务执行完毕-获取异步任务的返回值

33 System.out.println("future.get():" +future.get());34 } catch(InterruptedException e) {35 e.printStackTrace();36 } catch(ExecutionException e) {37 e.printStackTrace();38 }39 }40 //异步任务

41 static class Task implements Callable{42 //返回异步任务的执行结果

43 @Override44 public Integer call() throwsException {45 int i = 0;46 for (; i < 10; i++) {47 try{48 System.out.println(Thread.currentThread().getName() + "_"

49 +i);50 Thread.sleep(500);51 } catch(InterruptedException e) {52 e.printStackTrace();53 }54 }55 returni;56 }57 }58 }

View Code

2.2 FutureTask在高并发下确保任务只执行一次

在很多高并发的环境下,往往我们只需要某些任务只执行一次。这种使用情景FutureTask的特性恰能胜任。举一个例子,假设有一个带key的连接池,当key存在时,即直接返回key对应的对象;当key不存在时,则创建连接。对于这样的应用场景,通常采用的方法为使用一个Map对象来存储key和连接池对应的对应关系,典型的代码如下面所示:

1 private Map connectionPool = new HashMap();2 private ReentrantLock lock = newReentrantLock();3

4 publicConnection getConnection(String key){5 try{6 lock.lock();7 if(connectionPool.containsKey(key)){8 returnconnectionPool.get(key);9 }10 else{11 //创建 Connection

12 Connection conn =createConnection();13 connectionPool.put(key, conn);14 returnconn;15 }16 }17 finally{18 lock.unlock();19 }20 }21

22 //创建Connection(根据业务需求,自定义Connection)

23 privateConnection createConnection(){24 return null;25 }

View Code

在上面的例子中,我们通过加锁确保高并发环境下的线程安全,也确保了connection只创建一次,然而确牺牲了性能。改用ConcurrentHash的情况下,几乎可以避免加锁的操作,性能大大提高,但是在高并发的情况下有可能出现Connection被创建多次的现象。这时最需要解决的问题就是当key不存在时,创建Connection的动作能放在connectionPool之后执行,这正是FutureTask发挥作用的时机,基于ConcurrentHashMap和FutureTask的改造代码如下:

1 private ConcurrentHashMap>connectionPool = new ConcurrentHashMap>();2

3 public Connection getConnection(String key) throwsException{4 FutureTaskconnectionTask=connectionPool.get(key);5 if(connectionTask!=null){6 returnconnectionTask.get();7 }8 else{9 Callable callable = new Callable(){10 @Override11 public Connection call() throwsException {12 //TODO Auto-generated method stub

13 returncreateConnection();14 }15 };16 FutureTasknewTask = new FutureTask(callable);17 connectionTask =connectionPool.putIfAbsent(key, newTask);18 if(connectionTask==null){19 connectionTask =newTask;20 connectionTask.run();21 }22 returnconnectionTask.get();23 }24 }25

26 //创建Connection(根据业务需求,自定义Connection)

27 privateConnection createConnection(){28 return null;29 }

View Code

经过这样的改造,可以避免由于并发带来的多次创建连接及锁的出现。

futuretask java_java的FutureTask类相关推荐

  1. futuretask java_Java并发编程一(FutureTask)

    一.前言 创建线程有几种方式? 继承 Thread 类 实现 Runnable 接口 但这两种方式创建的线程是属于"三无产品": 没有参数 没有返回值 没办法抛出异常 用着 &qu ...

  2. math.hypot java_Java之Math类

    Java之Math类# Java的Math类封装了很多与数学有关的属性和方法,后续遇到常用也会直接在这篇博客更新...### public static void t2() { System.out. ...

  3. 反射工具类 java_Java反射工具类

    importjava.lang.reflect.Field;importjava.lang.reflect.Method;/*** Java反射工具类 * 提供以下几个功能: * 1. 取最简类名 * ...

  4. 动态调用类 java_Java动态调用类中方法

    在Java中,调用类的方法有两种方式:对于静态方法可以直接使用类名调用,对于非静态方法必须使用类的对象调用.反射机制提供了比较另类的调用方式,可以根据需要指定要调用的方法,而不必在编程时确定.调用的方 ...

  5. hashcode java_java 的Object类的hashcode()方法具体是怎么实现的?

    轻松解说Object.hashcode()的实现,让你看着不累! intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) ...

  6. 泛型类java_Java泛型 - 通用类( Generic Classes)

    Java泛型 - 通用类( Generic Classes) 泛型类声明看起来像非泛型类声明,除了类名后跟一个类型参数部分. 泛型类的类型参数部分可以有一个或多个用逗号分隔的类型参数. 这些类称为参数 ...

  7. deflater java_java.util.zip 类 Deflater - Java 中文参考手册

    java.lang.Object java.util.zip.Deflater public class Deflaterextends Object 此类使用流行的 ZLIB 压缩程序库为通用压缩提 ...

  8. a类怎么引用b类java_Java中A类的数组如何传入B类???急

    public class Test { public static void main(String[] args) { //方法一:引用传递 //创建A对象并给数组赋值 A a = new A(); ...

  9. preference java_Java使用Preference类保存上一次记录的方法

    本文实例讲述了Java使用Preference类保存上一次记录的方法.分享给大家供大家参考.具体分析如下: 在使用java中JFileChooser选择文件的时候,我们总希望在下次打开的时候能保存上次 ...

最新文章

  1. python中in的底层实现_python中print和input的底层实现
  2. PyQt4 Python GUI窗体应用程序
  3. 子网,变长子网及超网(CIDR)
  4. 有关计算机发展的英语作文,写一篇英语短文,介绍电脑的发展变化,并谈谈你对电脑的看法并翻译...
  5. Vmware下CentOs7 桥接模式下配置固定IP
  6. socket、端口、进程的关系
  7. Docker基础知识:Containers,Namespace,CGroups
  8. Visual C#中用WMI控制远程计算机
  9. js中中括号,大括号使用详解
  10. python水仙花数的代码_使用python求水仙花数的代码
  11. idc机房安装服务器系统,IDC机房如何部署IP KVM
  12. nodejs+express留言板功能实现
  13. 样本量估算:随机对照试验(两组均数)比较的样本量计算方法
  14. 图片转Word文档怎么转
  15. 什么是原码,1’s Complement Code反码和2’s Complement Code补码
  16. GO语言Comma-ok断言
  17. 如何用移动硬盘备份计算机,移动硬盘妙用 教你安装备份Win7系统
  18. 百万调音师—Audition初识
  19. 解析单存储库:定义、优势与挑战
  20. 计算机音乐b型谱简单,《神奇秘谱》琴曲的调弦法

热门文章

  1. 视觉螺丝机应用解决方案
  2. 职场生存--赞美别人
  3. Hive SQL间断日期补数
  4. QGC添加自定义组件和发送自定义MAVLINK消息
  5. WEB服务器和HTTP服务器(http server)和应用服务器的区别?(web服务器就是HTTP服务器)为什么要把Web服务器独立配置,和应用程序服务器一前一后?
  6. houdini vellum 显卡驱动造成解算崩溃笔记
  7. mysql中家庭关系_家庭数据库是什么
  8. java静态内部类有什么好处6_java的内部类和静态内部类(嵌套类)
  9. Excel2000/XP和PowerPoint2000/XP下内部COM插件的实现
  10. 史上最全docker安装方法!