futuretask java_java的FutureTask类
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类相关推荐
- futuretask java_Java并发编程一(FutureTask)
一.前言 创建线程有几种方式? 继承 Thread 类 实现 Runnable 接口 但这两种方式创建的线程是属于"三无产品": 没有参数 没有返回值 没办法抛出异常 用着 &qu ...
- math.hypot java_Java之Math类
Java之Math类# Java的Math类封装了很多与数学有关的属性和方法,后续遇到常用也会直接在这篇博客更新...### public static void t2() { System.out. ...
- 反射工具类 java_Java反射工具类
importjava.lang.reflect.Field;importjava.lang.reflect.Method;/*** Java反射工具类 * 提供以下几个功能: * 1. 取最简类名 * ...
- 动态调用类 java_Java动态调用类中方法
在Java中,调用类的方法有两种方式:对于静态方法可以直接使用类名调用,对于非静态方法必须使用类的对象调用.反射机制提供了比较另类的调用方式,可以根据需要指定要调用的方法,而不必在编程时确定.调用的方 ...
- hashcode java_java 的Object类的hashcode()方法具体是怎么实现的?
轻松解说Object.hashcode()的实现,让你看着不累! intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) ...
- 泛型类java_Java泛型 - 通用类( Generic Classes)
Java泛型 - 通用类( Generic Classes) 泛型类声明看起来像非泛型类声明,除了类名后跟一个类型参数部分. 泛型类的类型参数部分可以有一个或多个用逗号分隔的类型参数. 这些类称为参数 ...
- deflater java_java.util.zip 类 Deflater - Java 中文参考手册
java.lang.Object java.util.zip.Deflater public class Deflaterextends Object 此类使用流行的 ZLIB 压缩程序库为通用压缩提 ...
- a类怎么引用b类java_Java中A类的数组如何传入B类???急
public class Test { public static void main(String[] args) { //方法一:引用传递 //创建A对象并给数组赋值 A a = new A(); ...
- preference java_Java使用Preference类保存上一次记录的方法
本文实例讲述了Java使用Preference类保存上一次记录的方法.分享给大家供大家参考.具体分析如下: 在使用java中JFileChooser选择文件的时候,我们总希望在下次打开的时候能保存上次 ...
最新文章
- python中in的底层实现_python中print和input的底层实现
- PyQt4 Python GUI窗体应用程序
- 子网,变长子网及超网(CIDR)
- 有关计算机发展的英语作文,写一篇英语短文,介绍电脑的发展变化,并谈谈你对电脑的看法并翻译...
- Vmware下CentOs7 桥接模式下配置固定IP
- socket、端口、进程的关系
- Docker基础知识:Containers,Namespace,CGroups
- Visual C#中用WMI控制远程计算机
- js中中括号,大括号使用详解
- python水仙花数的代码_使用python求水仙花数的代码
- idc机房安装服务器系统,IDC机房如何部署IP KVM
- nodejs+express留言板功能实现
- 样本量估算:随机对照试验(两组均数)比较的样本量计算方法
- 图片转Word文档怎么转
- 什么是原码,1’s Complement Code反码和2’s Complement Code补码
- GO语言Comma-ok断言
- 如何用移动硬盘备份计算机,移动硬盘妙用 教你安装备份Win7系统
- 百万调音师—Audition初识
- 解析单存储库:定义、优势与挑战
- 计算机音乐b型谱简单,《神奇秘谱》琴曲的调弦法
热门文章
- 视觉螺丝机应用解决方案
- 职场生存--赞美别人
- Hive SQL间断日期补数
- QGC添加自定义组件和发送自定义MAVLINK消息
- WEB服务器和HTTP服务器(http server)和应用服务器的区别?(web服务器就是HTTP服务器)为什么要把Web服务器独立配置,和应用程序服务器一前一后?
- houdini vellum 显卡驱动造成解算崩溃笔记
- mysql中家庭关系_家庭数据库是什么
- java静态内部类有什么好处6_java的内部类和静态内部类(嵌套类)
- Excel2000/XP和PowerPoint2000/XP下内部COM插件的实现
- 史上最全docker安装方法!