Java当中,Lock和Condition一起使用的时候,可以实现多条件的并发,一个最简单的例子就是阻塞队列,它的实现需要两个条件变量,一个是队列不为空,另一个是队列不能满。

一个简单的例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class BlockedQueue<T>{
final Lock lock = new ReentrantLock();
// 条件变量:队列不满
final Condition notFull = lock.newCondition();
// 条件变量:队列不空
final Condition notEmpty = lock.newCondition();
// 入队
void enq(T x) {
lock.lock();
try {
while (队列已满) {
// 等待队列不满,这里就是阻塞线程
notFull.await();
}
// 省略入队操作...
// 入队后,通知可出队,这里是有元素入队后,满足条件,然后唤醒线程
notEmpty.signal();
} finally {
lock.unlock();
}
}
// 出队
void deq() {
lock.lock();
try {
while (队列已空) {
// 等待队列不空
notEmpty.await();
}
// 省略出队操作...
// 出队后,通知可入队
notFull.signal();
} finally {
lock.unlock();
}
}
}

同步与异步

通俗点来讲就是调用方是否需要等待结果,如果需要等待结果,就是同步;如果不需要等待结果,就是异步

异步实现的方法:

1、调用方创建一个子线程,在子线程中执行方法调用,这种调用我们称为异步调用;

2、方法实现的时候,创建一个新的线程执行主要逻辑,主线程直接 return,这种方法我们一般称为异步方法。

Dubbo的异步实现逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 创建锁与条件变量
private final Lock lock = new ReentrantLock();
private final Condition done = lock.newCondition();
// 调用方通过该方法等待结果
Object get(int timeout) {
long start = System.nanoTime();
lock.lock();
try {
while (!isDone()) {
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;
if (done != null) {
done.signal();
}
} finally {
lock.unlock();
}
}