3

AsynchronousByteChannel.read()の Javadoc には、操作が非同期で行われると書かれていますが、ストリームの終わりに到達するとどうなりますか? 実装は、read() を呼び出した同じスレッド内で完了ハンドラーを起動できますか? 実装の観点からは、結果が既にわかっているため、この操作を非同期で実行する理由はありません。同様に、ユーザーが、remaining() が 0 を返す ByteBuffer に読み込もうとすると、読み取り操作は 0 を返さなければならないことがわかります。

私自身の AsynchronousByteChannel 実装で競合状態に陥ったため、質問します。操作が完了すると、それ自体で notify() を呼び出す完了ハンドラーを呼び出しています。次に、次のユーザー コードを呼び出します。

CompletionHandler<?, ?> handler = ...;
synchronized (handler)
{
  asyncByteChannel.read(handler);
  handler.wait();
}

ユーザーは、操作が完了するとハンドラーに通知されると想定していますが、read() は実際には完了ハンドラーを同期的に呼び出すため、wait() の前に通知され、後者は永久にブロックされます。

仕様では、別のスレッドで CompletionHandler を更新する必要がありますか?それとも、read() を呼び出すスレッドが一部の操作を同期的に実行する可能性があるという事実をユーザーが認識する必要がありますか?

4

2 に答える 2

1

ハンドラーが別のスレッドで呼び出された場合でも、メソッドが戻った後read、つまり開始した後に呼び出されるという保証はありませんwait()。(わかりました、同期ロックがこれを保証しているようです。)

待機とロックには、同期とブール変数を使用する必要があります。

CompletionHandler<?, ?> handler = ...;
synchronized (handler)
{
   asyncByteChannel.read(handler);
   while(!handler.finished) {
     handler.wait();
   }
}

...そして、ハンドラーはfinished変数をtrueに設定します。

于 2011-07-12T15:34:31.437 に答える
1

http://www.docjar.com/html/api/sun/nio/ch/AsynchronousSocketChannelImpl.java.htmlを見ると、常に別のスレッドで CompletionHandler が更新されますが、Future は同じスレッドで更新されます。変数hasSpaceToReadを検索して、問題のメソッドを見つけます。

彼らの推論は次のようになると思います。

  1. ユーザーに返される Future を作成するため、オブジェクトを返す前に、ユーザーが Future とやり取り (同期など) することはありません。
  2. ユーザーが CompletionHandler を作成するため、実装の動作を制御する方法がありません (わかっている限りでは、デッドロックを引き起こす可能性があります!)。チャンスを逃さず、別のスレッドで完了ハンドラーを起動してください。

更新:私は訂正しました。Invoker.invoke()によると、「現在のスレッドがチャネル グループのスレッド プールにある場合、ハンドラーは直接呼び出されます。それ以外の場合は、間接的に呼び出されます。」

解決済み: http://download.oracle.com/javase/7/docs/api/java/nio/channels/AsynchronousChannelGroup.htmlによると、「I/O 操作がすぐに完了し、開始スレッドがプールされたスレッドの 1 つである場合グループ内のスレッドの場合、完了ハンドラーは開始スレッドによって直接呼び出される可能性があります。」

于 2011-07-12T16:50:05.923 に答える