-ThreadLocal再考察(1)

いろいろ想定コーディングを考えてみて、おそらくThreadLocalを利用した既存フレームワークをNon blockingなWEBコンテナの上でも大丈夫かなと。Grizzlyの中にTaskという概念/インターフェイスがありますが、以下のとおりです。

  • 接続処理
    • Grizzly:AcceptTaskというインターフェイスを実装する
    • nio:OP_ACCEPTというイベント名でSelector(nioクラス名。いわばイベントキュー)に保存される
    • 動作:クライアントからの接続要求に応答する。
  • 読み込み処理
    • Grizzly:ReadTaskというインターフェイスを実装する
    • nio:OP_READ
    • 動作:クライアントから到着するリクエスト電文を読む。
  • ビジネスロジック&書き込み処理
    • Grizzly:ProcessorTaskというインターフェイスを実装する
    • nio:OP_WRITE
    • 動作:リクエスト電文に応じて処理を行う。DBアクセスしたり、画面遷移したり、応答書き出しをすいる。

Servlet API上で動作するものについては、この処理タスクの局面だけがアプリケーションレベルで介入可能なところですから、ThreadLocal利用も大丈夫でしょう。確実に同一コールスタック中(Servlet#service()メソッド)で物事が終わるはずですからね。難しく考えすぎたみたいです。
一方でNon Blockingによってスレッド消費が抑えられるというのは、通信には必ず待ち時間が発生することと、何かのプログラミング上の処理はかならずスレッドを消費するコールスタックによって行われることに対する省力化ギミックです。先の接続タスク、読み込みタスク、書き込みタスクすべてについてスレッドは必要なのですが、接続のハンドシェイク処理等に関わる時間、クライアントから続々と到着するパケットが全部届くのを待つ時間はOSの提供するソケット関連の機能にまかせて、アプリケーションとしてスレッドを割り当てておかなくてもいい時間であるというのが手品のタネです。この時間がいかにブロードバンド化されネットワークが高速になろうともコンピューターの演算処理時間に比べてとてつもなく長い時間単位であることは変わらず、システム全体としてみると常にボトルネックとなります。Blockingはこの接続-読み込み-書き出しの一連を、スレッドをずっと占有してOSの提供するソケットの完了待ちを適宜しながら手順を踏むという仕組みですが、Non-Blockingは適宜これらの処理を分割し、発生毎にIOイベントのキューに保存しておき、それぞれの分割された処理が完了したものを順にキューから取り出して続く処理を行います。無駄な待ち時間を省いたためにリクエストに対するスレッド占有は複数になりますが、トータルの占有時間が短く、よってNon-Blockingのほうがスレッド消費しないシステムを作れるという結論となります。
でも、プログラムされるビジネスロジックそれぞれには必ずスレッドは割り当てられているわけですよ。それはBlockingであろうともNon-Blockingであろうとも変わらず、私の先日の考察中では粒度把握がまちがってました。