原理分析リユースOkHttp2接続プール

I.概要

  ネットワーク要求を実行し、応答を受信するためのHttpClient call.enqueue(コールバック)を作成するための最後の呼び出しからの話では、ソースコードの解析処理OkHttp3の結果。プロセスダウン分析は、私たちは私たちがいない残りの問題の分析に分析し、全体実行プロセスの基礎を理解する上で、このフレームワークを理解するのに役立ちます。例:接続プールOkHttp3を多重化します。

第二に、接続プールの原則

  ポイントOkHttp3はOkHttpがレスポンスを高速化するネットワーク遅延のネットワーク要求を減らすことができ、多くの学生が知っている方法を知っています。だから、それをどのように行うのでしょうか?これを言っ前に、我々は簡単にHTTPプロトコルを確認します。プロトコルはコネクションレスプロトコルであるHTTP、クライアント(リクエストのリクエストヘッダ+本体)は、サーバに要求を送信し、サーバは、応答(リクエストのリクエストヘッダ+本体)のデータ(レスポンスヘッダとその対応)とリターンを受け取ります。Httpの基礎となるプロトコルの実装がTCPプロトコルに基づいているように、4つの3ウェイハンドシェイクおよび放出リソースに振る、(正確なデータ到着を確実にするため)+応答およびTCPの最終的に必然的なプロセスを要求します。私たちは、そう、クライアントの要求とスリーウェイハンドシェイクと第四の波を通過するには、サーバーの応答のTCP必要性につき未接続の状態に応じて、クライアントがサーバにハートビートごとにパケットを送信するために10秒かかり、そのようなAの状況があることを前提としスリーウェイハンドシェイクや状況のフィールドの頭の除去は頻繁にも非常に心配である4つのネットワーク・パフォーマンスを振っていても、再三の要求に真剣にネットワークのパフォーマンスに影響する高周波を送ります。リンクは、それによって握手それの数を減らし、故障した際のタイムアウトを要求するために等しいがあれば聞かせする方法、一定期間のHTTPリンクがあり、このリンクを多重化?答えはイエス、OkHttp3は、私たちはより良い設計を支援してきましたさ。

   OkHttp3接続プーリングの原則:多重リンクにOkHttp3のConnectionPool使用接続プーリングは、原則は次のとおりです。要求は、ユーザーが開始されたときに、あなたが使用する必要がある場合は、最初にすべてのリンクのプールをチェック内のリンクの要件の遵守があるかどうか、(ここで発生する多重化)要求を開始するためのリンクを作成していない場合は、このリンクは、ネットワーク要求を開始します。この多重化メカニズムが大幅にネットワークの遅延を削減し、ネットワーク要求と応答のスピードを加速することができます。

第三に、ソースコード解析

  私たちは、主にそれが実装されている方法を確認するために、ソースコードのConnectionPool接続プールを見て、私たちは、スプリットのセクションを楽しみにしています。

民間最終int型のmaxIdleConnections、各アドレスのアイドル接続の最大数//
最終keepAliveDurationNsロングプライベート; 
民間最終のDeque <RealConnection>接続新しい新しいArrayDeque = <>();ダブルエンドリストの結果であり、頭部と尾部に挿入された支持要素、およびLIFOキューである//接続プール、
最終RouteDatabase routeDatabaseは新しいRouteDatabaseを()= ; // ルーティングリンク障害のレコード
ブールcleanupRunningを。
  プライベート静的最終エグゼキュータは=て、新しいThreadPoolExecutor(0 / *スレッドのコア数* /、
      Integer.MAX_VALUEの/ *スレッドプール内のスレッドの最大数* /スレッドプール内* /、60L / *最大アイドル時間スレッド* /、TimeUnit.SECONDS、/ *アイドル時間単位を収容することができます
      新しいSynchronousQueue <Runnableを>()/ * 実行可能なスレッドプールの実行方法により提出したタスクキューのスレッドプールは* /、Util.threadFactory(真の「OkHttpのConnectionPool」、)このキューに配置されます
と/ *ツールスレッドを作成するために、プロトタイプはThreadFactoryです* /);

  上記のコードを見ることができることによって、のConnectionPoolは、未使用のリンク(ソケット)を一掃することで、この役割のスレッドプールのスレッドプールを作成します。接続プールを置くためのリンクを追加するための独自の方法を使用してのConnectionPool(それぞれがリンクRealConnectionです)

PUTボイド(RealConnection接続){ 
   新しいキーワードで//java1.4、偽の例外をスローする場合は異常は、真でない場合 アサート(Thread.holdsLock(この));
  //クリアスレッドプールのアイドルソケットの使用 (もし!cleanupRunning){ cleanupRunning =はtrue。 executor.execute(cleanupRunnable)。 }
  //プールをリンクするためのリンクを追加します。 connections.add(接続)。 }

  上記のコードによって、我々は、リンク(RealConnection)を添加すると、スレッドプールに追加されることを見出した接続プールの接続に実際RealConnectionあります。そして、リンクをクリーンアップする方法ゾーンを実行するアイドルスレッドプールを呼び出す必要性を追加する前に。

ここでは、実装されているアクションをクリーンアップする方法を見て、直接見cleanupRunnable匿名の内部クラス

 民間最終RunnableをcleanupRunnable =新しいRunnableを(){
    公共のボイドRUNの@Override(){ 
   //無限ループは、常にクリーンアップクリーンアップを実行します 一方、(真の){
     //次のクリーンアップ間隔を返します (System.nanoTimeの()へ)クリーンアップwaitNanos =ロング;
    //停止直接的であれば-1 IF(waitNanos == -1)リターン;
    //次回いくつかのきれいな0以上の場合 IF(waitNanos> 0){ ロングwaitMillis = waitNanos / 1000000L。 waitNanos - =(waitMillis * 1000000L)。 同期(ConnectionPool.this){ {試みは、
        ロック解除待ちに応じた間隔//戻り、次の時間を ConnectionPool.this.wait(waitMillis、(int型)waitNanos)。 }キャッチ{(InterruptedExceptionが無視されます) } } } } } }。

  Runnableを内アイドルリンクをクリーンアップし、この間隔に基づいてロック待機時間を解放するために、クリーンアップに次の時間間隔を返すために、クリーンアップを呼び出して、無限ループの実行を停止することはありません。

  次の見た目の詳細なクリーンアップステップ

長いクリーンアップ(長今){
    int型inUseConnectionCount = 0;使用されているリンクの数//
    int型idleConnectionCount = 0;アイドルリンクの//数
  長い//アイドルリンク RealConnection longestIdleConnection = NULL; 長いlongestIdleDurationNs = Long.MIN_VALUE。 //接続プールを通過するforループ 同期(本){ {(; i.hasNext()イテレータ<RealConnection> iがconnections.iteratorを()=)のために RealConnection接続= i.next()。 //現在のリンクを使用している場合、実装は引き続き、次のサイクルを入力します。 もし(現在pruneAndGetAllocationCount(接続)> 0){ inUseConnectionCount ++; 継続する; }      //そうでない場合はアイドルリンク1 idleConnectionCount ++; //アイドル時間間隔が、最大リンクアイドル時に割り当てられ、その後、現在のリンクの最大アイドル時間よりも大きい場合。 今長いidleDurationNs = - connection.idleAtNanos。 IF(idleDurationNs> longestIdleDurationNs){ longestIdleDurationNs = idleDurationNs。 longestIdleConnection =接続; } }     //最大アイドル時間間隔は、接続プールから削除された最大時間間隔よりも大きいか、アイドル状態の接続数の最大数は、リンクを置くために、許容接続プールより大きいリンクの制限を維持することである場合 もし(longestIdleDurationNs> = this.keepAliveDurationNs || idleConnectionCount> this.maxIdleConnections){ connections.remove(longestIdleConnection)。 }そうであれば(idleConnectionCount> 0){ //アイドルリンク数は、リンクリターンままに許容される最大時間間隔がゼロよりも大きい場合 - 次の時間間隔を返すことで、最大時間間隔、 リターンkeepAliveDurationNs - longestIdleDurationNs。 }そうであれば(inUseConnectionCount> 0){ すべてのリンクが使用されている場合、//その後、直接バックの最大時間間隔を維持します リターンkeepAliveDurationNs; } そうしないと { //上記の条件が満たされない場合、インシデントがクリアされ、リターン-1 cleanupRunning = falseは、 -1を返します。 } }   //ソケット最長アイドル時間を閉じます closeQuietly(longestIdleConnection.socket())。 //クリーンアップ再びすぐ。 0を返します。 }  

クリーンアップ(今)この方法は、比較的長く、内容がよりになります。私たちは、ライン上の一般的なロジックを把握します。コアロジックは次の時間間隔をクリーンアップするために返され、コアのクリーンアップは次のとおりです。時間制限リンクは、ユーザーまたはアイドル時間によって上限セットリンクの数は、クリーンアップ操作の実装に、ユーザーが最大数のセットを超えているよりも大きい場合。4つの値のその次のクリーンアップ間隔:

  その最長のアイドル接続のアイドル時間 - 接続数が0戻りより大きい場合1.アイドル時間が設定限界をユーザに可能にします。

  2.クリーンアップは-1を返すのに失敗した場合、

  3.クリーンアップに成功リターン0の場合、

  4.アイドルリンクが存在しない場合は、ユーザーが直接最大のクリーンアップの時間間隔セットを返します。

システムがリンクを決定することであるかで次の外観は、使用されている現在のサイクルへのリンクです

int型pruneAndGetAllocationCountプライベート(ロング今RealConnection接続、){ 
  //弱参照リストのコンパイルStreamAllocation リスト<参考<StreamAllocation >>参照= connection.allocations。 以下のために(INT iが= 0; I <references.size()){ 参照<StreamAllocation>基準= references.get(I)。     //もしStreamAllocationが空の散歩を続けられない、カウンター+ 1; もし(reference.get()!= NULL){ I ++; 継続する; } //私たちは、漏洩した割り当てを発見しました。これは、アプリケーションのバグです。 StreamAllocation.StreamAllocationReference streamAllocRef = (StreamAllocation.StreamAllocationReference)参照。 //リストを削除し、空の参照です references.remove(I); connection.noNewStreams =はtrue。 この最終//割り当てにあった場合は、接続時に負荷の即時退去の対象となります。
    //リストは、それが0を返す空の場合 IF(references.isEmpty()){ 今connection.idleAtNanos = - keepAliveDurationNs。 0を返します。 } } リターンreferences.size(); }

  以上により、我々は弱参照リストを横断するコードを見ることができ、リストがnull参照であり、リスト番号を返します。<= 0 RealConnectionのアイドル状態を示す場合> 0返さの数はRealConnectionが活性を示す場合。すなわち、現在のリンクがアイドルリンクではないかを決定するために、このメソッドを使用します。

  私たちは見てみましょう

closeQuietly(longestIdleConnection.socket());最長リンクアイドルをオフにする方法。
パブリック静的ボイドcloseQuietly(ソケットソケット){
    もし(ソケット!= NULL){
      {試します
        socket.close();
      }キャッチ(AssertionErrorを電子){
        (もし!isAndroidGetsocknameError(e)参照)スロー電子;
      }キャッチ(のRuntimeExceptionの再スロー){
        再スローを投げます。
      }キャッチ{(例外は無視しました)
      }
    }
  }

  実際には、一行にコアコード)(socket.close。使用ソケットは、もはや私たちは、物品の特別なクラスを参照してくださいすることができ、導入されません。

私たちは、新たなリンクが接続プールに追加されるまで、接続プールからクリーンアップのアイドルリンクを分析しました。接続多重化が達成されるだけでなく、接続を使用する方法で見てみましょう

  @Nullable RealConnection GET(アドレスアドレス、StreamAllocation streamAllocation、国道ルート){
    アサート(Thread.holdsLock(この));
    {(接続RealConnection接続)のために
      IF(connection.isEligible(アドレス、ルート)){
        streamAllocation.acquire(接続、真の);
        接続を返します。
      }
    }
    ヌルを返します。
  }

  その後、別の中の場所を作成し、ヌルを再生しない場合は、リンクの要件の遵守がある場合、戻りの使用への直接リンクがあるかどうか、確認するために接続プールをループするforループを使用して、リンク接続プールロジックは非常に単純でゲット接続プールに新しいRealConnection。ここでコアコードは、リンクの条件の遵守があるかどうかを決定することである。connection.isEligible(アドレス、ルート)

パブリックブールisEligible(アドレスアドレス、@Nullableルートルート){
    //リンクの数は、現在の技術の制限のサイズよりも大きい、または、このリンク上のストリームを作成することができない場合は、単にfalseを返します
    (allocations.size()> = allocationLimit || noNewStreams)戻り場合はfalse;

    //ホストアドレスフィールドに直接矛盾するとfalseの場合
    (もし!Internal.instance.equalsNonHost(this.route.address()、アドレス))のリターンはfalse;

    ホストアドレスが一致した場合//我々は、接続を再利用しました
    IF(address.url()。ホスト()。等号(this.route()アドレス()。URL()。ホスト())){
      trueを返します。//この接続は完璧にマッチです。
    }

   ......

    trueを返します。
  }

 ここでの分析、接続プールが分析されているし、次のおさらい

要約:

  接続プールを作成します。1.

    接続プールを作成することは、単にライン上のオブジェクトを作成するために、新しいキーワードを使用し非常に簡単です。新しいのConnectionPool(maxIdleConnections、keepAliveDuration、TIMEUNIT)

    パラメータ:

      接続の最大数は、接続プールのアイドル1.maxIdleConnectionsによって許可しました

      接続タイムアウトリンク2.keepAliveDuration遺骨は、プールで許可します

      3.timeUnit時間保持ユニットリンクタイムアウト時間

  接続プールへの接続を追加します。2.

    リンクに参加することは、第1のアイドルリンクをクリーンアップするcleanupRunnable匿名内部クラスを実行すると、リンクがキューのDequeに参加するスレッドプールを呼び出す前にリンクを追加することもできます。(realConnection)メソッドは、のConnectionPoolを置きます

    B。cleanupRunnable匿名内部クラスで無限ループを実行し、次の時間間隔をクリーンアップするConnectionPool.waitメソッドを呼び出して、クリーンアップ次の時間間隔をアイドル状態の接続とリターンをクリーンアップするクリーンアップを呼び続け

    C。接続プール接続の内部クリーンアップでは、キュー、削除アイドル最長の接続と戻り、次のクリーンアップ時間を横断します。

    dが。接続は、サイズがRealConnection一覧<参考<StreamAllocation>内部のアイドルの使用であるか否かを判断します。サイズあれば後述するサイズ> 0は、アイドル状態でない場合<= 0は、アイドルを説明します。

  リンクを取得します。3.

    ConnectionPoolのgetメソッドによりRealConnectionの要件を満たすために取得します。あなたはRealConnectionサービスを返すように要求し、それがnullを返すための要件を満たし、かつRealConnectionの外側を再作成し、リンクを開始しない場合は、リンクで要求を開始している場合。リンクの数は、現在の技術の制限サイズのより大きい場合、またはこのリンク上のストリームを作成することはできません、ホストアドレスが直接バックfalse3正確な我々は接続を再利用します一致する場合、アドレスフィールドが矛盾ホストである場合は、単純に偽の2を返す場合1.条件を決定します。

 

 

  

 

おすすめ

転載: www.cnblogs.com/tony-yang-flutter/p/12383267.html