Java并发15:Lock&Condition-2
Java代码默认同步处理。
通过两种方式实现异步:
- 调用方创建一个子线程,在子线程方法中调用,即异步调用。
- 方法实现时,创建一个新线程执行主要逻辑,主线程直接
return
,即异步方法。
Dubbo源码分析
RPC 调用,在 TCP 协议层面,发送完 RPC 请求后,线程不会等待 RPC 的响应结果。
但平常中的RPC调用大多是同步的,如Dubbo中的DefaultFuture.get()
方法,就是帮忙做了异步转同步操作。
Dubbo中的DefaultFuture
类的精简代码(2.7.3版本已不用lock和signal了)。
// 创建锁与条件变量
private final Lock lock = new ReentrantLock();
private final Condition done = lock.newCondition();
// 调用方通过该方法等待结果
Object get(int timeout){
//记录请求发起时间
long start = System.nanoTime();
//锁定资源
lock.lock();
try {
//循环判断请求是否完成 MESA管程模型wait()范式
//若未完成,就继续wait
while (!isDone()) {
//condition设置超时wait
done.await(timeout);
//记录当前执行时间
long cur=System.nanoTime();
//如果此时完成 或者 已超时 跳出循环
if (isDone() || cur-start > timeout){
break;
}
}
} finally {
lock.unlock();
}
//未完成抛异常
if (!isDone()) {
throw new TimeoutException();
}
//完成后返回请求完成的结果
return returnFromResponse();
}
// RPC结果是否已经返回
boolean isDone() {
return response != null;
}
// RPC结果返回时调用该方法
private void doReceived(Response res) {
lock.lock();
try {
response = res;
//这边check done!=null 没必要 done必不为空
if (done != null) {
//后来改成了signalAll();
done.signal();
}
} finally {
lock.unlock();
}
}
别人的总结
DefaultFuture本质上只是一种future实现,所以理论上可以有多个线程同时持有同一个future并调用 get方法,如这时候使用signal()就有可能导致有些线程会请求超时
>DefaultFuture future = currentClient.request(inv, timeout); >for(int i=0; i< 10000; i++) { >new Thread(new Runnable() { >@Override >public void run() { System.out.println(future.get().toString()); >} >}); >}
——牧名