
实现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);
}
}*/
}
浙公网安备 33010602011771号