java如何实现一个Future
实现Futrue接口
public class MsgFuture<V> implements java.util.concurrent.Future<V> {
...
...
}
Future的主要特性为Future.get()、
get()
get(long timeout, TimeUnit unit)
主要思路如下:
构造MsgFuture时,设置开始时间,这里是sendTime;设置timeout,默认get()方法的超时时间,我们的程序不可能会无限等待
默认的get()对应的值域是result,默认为一个NULL对象,标识没有返回数据
result的值需要其他线程在做完任务后将值写到Future对象中,这里暴露了一个方法setResult(object)
/**
* 设置结果值result,唤醒condition {@link #get(long, TimeUnit)}
* @param result
*/
public synchronized void setResult(Object result) {
reentrantLock.lock();
try {
this.result = result;
condition.signalAll();
}finally {
reentrantLock.unlock();
} }
使用ReentrantLock来进行数据可见性控制
condition.signalAll()可以唤醒condition.await的阻塞wait
至于其他线程如何调用到setResult(object)方法,可以使用ConcurrentHashMap,key为msgId,值为MsgFuture对象,设置成一个全局的,或两个线程都可访问,其他线程根据msgId获取到MsgFuture,然后调用setResult(object)方法
/**
* 获取结果,如果到达timeout还未得到结果,则会抛出TimeoutException
* @param timeout
* @param unit
* @return
* @throws InterruptedException
* @throws TimeoutException
*/
@SuppressWarnings("all")
public V get(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
long left = getLeftTime(timeout, unit); //根据timeout配置获取剩余的世界
if(left < 0){
//已经没有剩余时间
if(isDone()){ //如果已经完成,直接放回结果
return (V)this.result;
}else{
//timeout
throw new TimeoutException("返回超时,后续的响应将会被丢弃abort");
}
}else{ reentrantLock.lock(); //同步
try {
//获取锁后先判断是否已经完成,防止无意义的await
if(isDone()){ //先判断是否已经完成
return (V)this.result; //直接返回
}
logger.debug("await "+left+" ms");
condition.await(getLeftTime(timeout, unit), TimeUnit.MILLISECONDS); //没有返回,阻塞等待,如果condition被唤醒,也会提前退出
}finally {
reentrantLock.unlock();
}
if(isDone()){ //被唤醒或超时时间已到,尝试判断是否完成
return (V)this.result; //返回
} throw new TimeoutException("未获取到结果"); //超时
}
}
public boolean isDone() {
return this.result != NULL;
}
全部代码
public class MsgFuture<V> implements java.util.concurrent.Future<V> { private final static Logger logger = LoggerFactory.getLogger(MsgFuture.class); /**
* 全局的空对象,如果Future获取到值了,那么一定不是NULL
*/
private final static Object NULL = new Object();
/**
* 主锁
*/
private final ReentrantLock reentrantLock = new ReentrantLock(); /**
* 条件,利用它的condition.await(left, TimeUnit.MILLISECONDS)和notifyAll方法来实现阻塞、唤醒
*/
private final Condition condition = reentrantLock.newCondition(); private int timeout; private volatile Object result = NULL; private long sendTime; public MsgFuture(int timeout, long sendTime) {
this.timeout = timeout;
this.sendTime = sendTime;
} public boolean cancel(boolean mayInterruptIfRunning) {
return false;
} public boolean isCancelled() {
return false;
} public boolean isDone() {
return this.result != NULL;
} /**
* 获取future结果
* @return
* @throws InterruptedException
*/
public V get() throws InterruptedException {
logger.debug("sendTime:{}",sendTime);
try {
return get(timeout, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
logger.error("获取future结果异常", e);
}
return null;
} /**
* 获取结果,如果到达timeout还未得到结果,则会抛出TimeoutException
* @param timeout
* @param unit
* @return
* @throws InterruptedException
* @throws TimeoutException
*/
@SuppressWarnings("all")
public V get(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
long left = getLeftTime(timeout, unit);
if(left < 0){
//已经没有剩余时间
if(isDone()){
return (V)this.result;
}else{
//timeout
throw new TimeoutException("返回超时,后续的响应将会被丢弃abort");
}
}else{ reentrantLock.lock();
try {
//获取锁后先判断是否已经完成,防止无意义的await
if(isDone()){
return (V)this.result;
}
logger.debug("await "+left+" ms");
condition.await(getLeftTime(timeout, unit), TimeUnit.MILLISECONDS);
}finally {
reentrantLock.unlock();
}
if(isDone()){
return (V)this.result;
} throw new TimeoutException("未获取到结果");
}
} /**
* 设置结果值result,唤醒condition {@link #get(long, TimeUnit)}
* @param result
*/
public synchronized void setResult(Object result) {
reentrantLock.lock();
try {
this.result = result;
condition.signalAll();
}finally {
reentrantLock.unlock();
} } /**
* 计算剩余时间
* @param timeout
* @param unit
* @return
*/
private long getLeftTime(long timeout, TimeUnit unit){
long now = System.currentTimeMillis();
timeout = unit.toMillis(timeout); // 转为毫秒
return timeout - (now - sendTime);
} /*public static void main(String[] args) {
MsgFuture msgFuture = new MsgFuture(2000,System.currentTimeMillis()); //测试先唤醒、后get是否正常
msgFuture.setResult("yoxi"); try {
System.out.println(msgFuture.get(2000,TimeUnit.MILLISECONDS));
} catch (InterruptedException e) {
logger.error("Interrupt异常", e);
} catch (TimeoutException e) {
logger.error("测试先唤醒,后get出错", e);
}
}*/
}
java如何实现一个Future的更多相关文章
- java多线程之Future和FutureTask
Executor框架使用Runnable 作为其基本的任务表示形式.Runnable是一种有局限性的抽象,然后可以写入日志,或者共享的数据结构,但是他不能返回一个值. 许多任务实际上都是存在延迟计算的 ...
- Java多线程编程中Future模式的详解
Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...
- Java多线程编程中Future模式的详解<转>
Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...
- Java 并发编程——Callable+Future+FutureTask
Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...
- 使用executor、callable以及一个Future 计算欧拉数e
package test; import java.math.BigDecimal; import java.math.MathContext; import java.math.RoundingMo ...
- 用Java语言编写一个简易画板
讲了三篇概博客的概念,今天,我们来一点实际的东西.我们来探讨一下如何用Java语言,编写一块简易的画图板. 一.需求分析 无论我们使用什么语言,去编写一个什么样的项目,我们的第一步,总是去分析这个项目 ...
- 如何在JAVA中实现一个固定最大size的hashMap
如何在JAVA中实现一个固定最大size的hashMap 利用LinkedHashMap的removeEldestEntry方法,重载此方法使得这个map可以增长到最大size,之后每插入一条新的记录 ...
- 利用java实现的一个发送手机短信的小例子
今天闲来无事,在微博上看到一个关于用java实现的一个发送手机短信的程序,看了看,写的不太相信,闲的没事,把他整理下来,以后可能用得着 JAVA发送手机短信,流传有几种方法:(1)使用webservi ...
- 教你如何使用Java手写一个基于链表的队列
在上一篇博客[教你如何使用Java手写一个基于数组的队列]中已经介绍了队列,以及Java语言中对队列的实现,对队列不是很了解的可以我上一篇文章.那么,现在就直接进入主题吧. 这篇博客主要讲解的是如何使 ...
随机推荐
- Unity 自己使用顶点描绘圆形UI图片
2020-09-10 在游戏的UI中,圆形图片的需求是很高的,但是,在Unity中想要实现圆形UI,一般的做法是是使用圆形Mask(遮罩),但是使用Mask的缺点很明显,主要有三点: 1.比较麻烦,使 ...
- 爬虫必看,每日JS逆向之爱奇艺密码加密,今天你练了吗?
友情提示:优先在公众号更新,在博客园更新较慢,有兴趣的关注一下知识图谱与大数据公众号,本次目标是抠出爱奇艺passwd加密JS代码,如果你看到了这一篇,说明你对JS逆向感兴趣,如果是初学者,那不妨再看 ...
- JavaScript创建对象的方式汇总
1.Object构造函数创建 // 1.Object构造函数创建 var Obj = new Object(); Obj.name='saoge'; Obj.say=function(){ conso ...
- lamda表达式与Stream 流操作,reduce,flatMap,groupingBy等
/** * 符合lambda表达式的接口也叫函数式接口: * 除了默认方法和Object类的方法外,只有一个抽象方法的接口才能符合lambda表达式的要求 * 可以使用@FunctionalInter ...
- sort函数居然能改变元素值?记一次有趣的Bug——四数之和
坐标leetcode: 我想都不想直接深度优先搜索暴力求解: class Solution { public: vector<vector<int>> res; //答案 in ...
- 排序算法:冒泡排序(Bubble Sort)
冒泡排序 算法原理 冒泡排序的原理是每次从头开始依次比较相邻的两个元素,如果后面一个元素比前一个要大,说明顺序不对,则将它们交换,本次循环完毕之后再次从头开始扫描,直到某次扫描中没有元素交换,说明每个 ...
- c++中 预编译头文件PCH
转载:https://blog.csdn.net/lovemysea/article/details/74858430 一.预编译头文件使用经验: 如果预编译头文件被正确使用时,它确实大大提高我们编程 ...
- HTML & CSS & JavaScript 从一个表格到一个灰阶颜色表 03
工具1:HBuilder X 1.9.9.20190522 工具2:火狐浏览器 67.0.4 (64 位) 其实,我还想使用表格,做一个这样的颜色表,如下图所示: 如果按照之前的做法,把每一种颜色都列 ...
- 程序员你是如何使用Nacos作为配置中心的?
假如你使用的是spring-cloud-alibaba微服务技术栈 单个服务独有配置文件 即去除应用程序的状态,配置统一外部化管理,方便进行水平的伸缩. 集成步骤: 假如我有一个应用app-desig ...
- Semaphore最详细解析
官方解释: 一个计数信号量.在概念上,信号量维持一组许可证.如果有必要,每个acquire()都会阻塞,直到许可证可用,然后才能使用它.每个release()添加许可证,潜在地释放阻塞获取方.但是,没 ...