条件は、管理モデルに条件変数を実装します。
組み込みJavaプログラムには条件変数が1つだけあり、Lock&Conditionによって実装された制御プログラムは複数の条件変数をサポートします。これは2つの条件変数の重要な違いです。
1. 2つの条件変数を使用してブロッキングキューをすばやく実装するにはどうすればよいですか?
ブロッキングキューには2つの条件変数が必要です。1つはキューが空でない(空のキューはキューから離れることができない)こと、もう1つはキューがいっぱいでない(キューがいっぱいでキューが許可されていない)ことです。
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();
}
}
}
ロックおよび条件実装の手順、スレッド待機および通知は、await()、signal()、signalAll()、それらのセマンティクスと待機()、notify()、notifyAll()のみを呼び出すことができ、同期によって管理プロセスを実現するために使用されます。同様に、2つの手順を実装するために使用される方法を間違えることはできません。
2.同期および非同期
簡単に言えば、それは呼び出し側が結果を待つ必要があるかどうかであり、必要な場合は同期的であり、そうでない場合は非同期的です。
非同期を実現する2つの方法:
- 呼び出し元はサブスレッドを作成し、サブスレッドでメソッド呼び出しを実行します。これは非同期呼び出しと呼ばれます。
- メソッドが実装されると、メインロジックを実行するための新しいスレッドが作成され、非同期メソッドと呼ばれるメインスレッドが直接戻ります。
3.ダボソースコードの分析
TCPプロトコル自体は非同期であり、TCPプロトコルレベルでは、RPC要求を送信した後、スレッドはRPCの応答結果を待ちません。
ダボは同期に対して非同期の何かをしました。
次の単純なRPC呼び出しでは、sayHello()メソッドはデフォルトで同期メソッドです。つまり、service.sayHello( "dubbo")が実行されると、スレッドは停止して結果を待ちます。
DemoService service = 初始化部分省略
String message = service.sayHello("dubbo");
System.out.println(message);
ダンプスレッドが出て、スレッドがブロックされ、ステータスがTIMED_WAITINGであることがわかりました。元々リクエストは非同期で送信されましたが、呼び出しスレッドはブロックされました。これは、ダボが非同期から同期への処理を行ったことを示しています。スレッドはDefaultFuture.get()メソッドでブロックされます。
DubboInvokerの108行目でDefaultFuture.get()を呼び出します。この行では、最初にrequest(inv、timeout)メソッドを呼び出します。このメソッドは実際にはRPC要求を送信し、次にget()メソッドを呼び出してRPCの戻り結果を待機しています。
public class DubboInvoker{
Result doInvoke(Invocation inv){
// 下面这行就是源码中 108 行
// 为了便于展示,做了修改
return currentClient
.request(inv, timeout)
.get();
}
}
関連するコードが簡素化され、要件が繰り返されます。RPCが結果を返したら、呼び出しスレッドをブロックして呼び出しスレッドを待機させます。RPCが結果を返したら、呼び出しスレッドを起動して、呼び出しスレッドを再度実行させます。クラシックな待機通知メカニズム。以下はダボの実装です
// 创建锁与条件变量
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();
}
}
呼び出し元のスレッドは、get()メソッドを呼び出してRPCが結果を返すのを待ちます。このメソッドでは、見慣れた「顔」がすべて見られます。lock()を呼び出してロックを取得し、最後にunlock()を呼び出してロックを解放します。ロックを取得した後、待機は、クラシックループでawait()メソッドを呼び出すことによって実現されます。
RPCの結果が返されると、doReceived()メソッドを呼び出します。このメソッドでは、lock()を呼び出してロックを取得し、最後にunlock()を呼び出してロックを解放します。ロックを取得したら、シグナル()を呼び出して、結果が返されたことを呼び出しスレッドに通知します、もう待つ必要はありません。