ビジネスの背景
プロジェクトは教室の先生が説明する書類に必要ネッティーが実装され、リアルタイムの教室プロジェクト、に基づいて、サーバーへの教師は、すべてのクライアント(生徒と教師)に論文に情報を送信、情報のオープンサーバは、紙情報を取得論文のリクエストを送信します。
用紙情報の私のスコア情報と相まって、学生のニーズに送られたとき。
次のように実装は次のとおりです。
。1紙用紙= getPaper(paperId); // 紙の詳細紙ID取得 2を するための(クライアントクライアント:allClients){ 3 paper.setMyScore(getMyScore(client.getUserId())); // useridはスコア取得 4 client.send(紙); // クライアントにデータを送信する 5 }
結果:スコアスコア学生生徒Bが受信され、データが紙に送られるクライアントAのデータがclientBを覆うように用紙に伝達され、オブジェクトは紙と同じです
分析:
情報は、ループ実行のために、すべてのクライアントが、sendメソッドで紙ターゲットに送信されているが、実行のsendメソッドが終わった後に、それは理論だけであり、理論的にことを意味し、実行clientBクライアントAの方法を送信する必要があり、紙は情報の学生Bは、紙情報を受信する受信した後、学生はする必要があります。
だから、結論は推測sendメソッドが非同期で同期的に実行されないが、です。トラッキングコード解析
コードは、四行目(紙)client.send writeAndFlushのチャンネル実用的な方法を呼び出すことです
以下を達成するためにAbstractChannelトラック:
1 @Override 2 公共ChannelFuture writeAndFlush(オブジェクトMSG){ 3 リターンpipeline.writeAndFlush(MSG)。 4 }
ChannelPipelineは、writeAndFlushの方法を実装 - 実装クラスDefaultChannelPipelineは以下の追跡します:
1 @Override 2 公共 最終ChannelFuture writeAndFlush(オブジェクトMSG){ 3 リターンtail.writeAndFlush(MSG)。 4 }
この方法は、実装クラスAbstractChannelHandlerContextは、以下を達成追跡、writeAndFlush ChannelHandlerContext実行されます。
1 @Override 2 公共ChannelFuture writeAndFlush(オブジェクトMSG){ 3 リターンwriteAndFlush(MSG、newPromise())。 4 }
WriteAndFlush方法は、以下に従うことを継続し、内部に行わ:
1 @Override 2 公共ChannelFuture writeAndFlush(オブジェクトMSG、ChannelPromiseの約束){ 3 であれば(MSG == NULL ){ 4 投 新しい NullPointerExceptionが( "MSG" )。 5 } 6 7 場合(isNotValidPromise(約束、真)){ 8 ReferenceCountUtil.release(MSG)。 9 // キャンセル 10 リターンの約束を。 11 } 12 13 ライト(MSG、真、約束)。 14 15 リターン約束する; 16 }
次のように記述します。
1つの プライベート ボイドライト(オブジェクトMSG、ブールフラッシュ、ChannelPromiseの約束){ 2 AbstractChannelHandlerContext次= findContextOutbound()。 3 最終物体M = pipeline.touch(MSG、NEXT)。 4 EventExecutorキュータ= next.executor()。 5 あれば(executor.inEventLoop()){ // 判断当前线程是否是イベントループ线程 6 場合(フラッシュ){ 7 next.invokeWriteAndFlush(M、約束)。 8 } 他{ 9 next.invokeWrite(M、約束)。 10 } 11 } 他{ 12 AbstractWriteTaskタスク。 13 であれば(フラッシュ){ 14 タスク= WriteAndFlushTask.newInstance(次、M、約束)。 15 } 他{ 16 タスク= WriteTask.newInstance(次、M、約束)。 17 } 18 safeExecute(エグゼキュータ、タスク、約束、M)。 19 } 20 }
次のようにトラック、ここでようやく私たちは、論理の方法を発見したのです。
1.ヘッドノードを取得しchannelPipeline
2.イベントループオブジェクトの現在のチャンネルを取得
現在のスレッドの場合はイベントループスレッドオブジェクトの現在のチャネルを決定するために3
4.イベントループスレッドは、書かれており、フラッシュ実行されwriteAndFlush直接実行方法は、channelSocketに行く場合
5.そうでない場合は、あなたがAbstractWriteTaskを作成し、チャネルの囲碁イベントループにこのタスクを追加イベントループのスレッド
ここでの分析は、スレッドがスレッドプールスレッドのチャネルが実行される作業ではありませんwriteAndFlush場合、それは最初にこのチャンネルが所属するタスクには、このパッケージにメッセージを送信した後、ブロックされたイベントループに追加されます、問題の概要となりますどこへ行くキュー、
そして、イベントループタスクはキューから実行されている循環によって取得しました。タスクが完了する方法リターンを書き込み、キューに追加。MSGの内容が同じオブジェクトであるため、ときに、次のクライアントとは、writeメソッドを実行し、だから、それはカバーするためにMSGの前にコンテンツになります。
これにより、異なる複数のコンテンツが存在するであろうことは、クライアントに送信されるが、コンテンツは受信したコンテンツと同じです。本実施例では、実行チャネル書き込み方式のスレッドがスレッドをイベントループはありません、我々はチャンネルデータがサーバーに送信されたときにトラフィックを処理するためにスレッドプールを使用しているため、
サーバは、チャネルが要求に伝達され解析し、サービス処理を行い、スレッドプールのようにして、実際のスレッドプール内のスレッドであるクライアントへのチャネルデータを介して、最終的な伝送、および実装されているサービスを実行する動作とイベントループは、スレッドがチャネルではありません属します。
要約:
イベントループスレッドプール網状ポーリングセレクタIO動作、タスクおよびタイミングシステムタスクに対処する意志に加えて、純粋なIOスレッドで動作していません。
ユーザスレッドがIO操作を開始したため、タスクシステムを達成するために(Runnableをタスク)メソッドはイベントループ内部イベントループLinkedBlockingQueueを実行しているが、通常は、ブロッキングキューがタスクを保存タスクを持っています。
各クライアントは、チャンネルを持って、各チャネルは、イベントループを結合するので、IO操作は、このスレッドでイベントループによって実行され、各チャネルのデフォルトです。ユーザーは、チャネル方法は、カスタムスレッドで実行することができます。
IO実行のスレッドのチャネルとを直ちに実行されないが、IO操作タスクにパッケージされ、ユーザの操作は、イベントループキューを対応するチャネルに加え、そして次にイベントループスレッドによって実行されます。だから、最終的には全てのIO操作チャンネル
ただ、どのスレッドではないかもしれないスレッドIO操作を実行するために、同じイベントループにスレッドによってチャンネルを立ち上げました。
、それが道をタスクでない場合、ユーザスレッドとIOのスレッドが同時にネットワークリソースを操作することができるので、IO操作は、タスクがロック競合同時演算結果を防ぐためであるカプセル化された理由を使用すると同時実行の問題を格納し、そのタスクの使用は、達成することを意味しています部分的ロックフリー技術。
だから、スレッドプールは、強力なもののネッティー使い、確かに簡単ですが、何の深い理解がない場合には、わずかなミスがBUGが表示され、予期しない可能性があります。