私は、マルチスレッド Java サーバーのパフォーマンスとランダム クラッシュの問題に取り組むように割り当てられました。スレッドとスレッド セーフは、私にとってまったく新しいトピックではありませんが、新しいマルチスレッド アプリケーションを設計することは、おそらくレガシー コードを微調整することの半分の難しさであることがわかりました。答えを求めてよく知られている本をざっと読みましたが、奇妙なことに、それについて読んで提供された例を分析する限り、すべてが明確に見えます. しかし、自分が取り組むべきコードを見た瞬間、何もわからなくなってしまいました! 理論的な知識が多すぎて、実際の経験がほとんどないに違いありません。
とにかく、話題に戻ると、オンラインで調査を行っていたときに、このコードに出くわしました。私を悩ませ続けている質問は、同期せずに 2 つの別々のスレッドからソケットで getInputStream() と getOutputStream() を呼び出すのは本当に安全かということです。それとも、スレッドセーフの問題全体について少し偏執的になりすぎていますか? 連続して 5 冊目の本のように、同時実行で問題が発生する可能性があることがいくつあるかを説明しているときに、それが起こると思います。
PS。質問が少し長かったり、あまりにも「初心者」だったりして申し訳ありませんが、お手柔らかにお願いします - これが私の最初の投稿です。
編集:明確にするために、ソケットが全二重モードで動作し、入力ストリームと出力ストリームを同時に使用しても安全であることを知っています。メイン スレッドでこれらの参照を取得し、それらを使用してスレッド オブジェクトを初期化する場合は問題ないように思えますが、これらのストリームを 2 つの異なるスレッドで取得しても安全ですか?
@rsp:
だから私はSunのコードをチェックPlainSocketImpl
して、あなたが言ったように、これら2つの方法で同期しています。Socket
ただし、そうではありません。getInputStream()
とgetOutputStream()
は のラッパーにすぎないSocketImpl
ため、おそらく同時実行の問題によってサーバー全体が爆発することはありません。それでも、少し不運なタイミングで、問題が発生する可能性があるようです(たとえば、メソッドが既にエラー状態をチェックしているときに、他のスレッドがソケットを閉じた場合)。
ご指摘のとおり、コード構造の観点から、ソケット全体ではなく、各スレッドにストリーム参照を提供することをお勧めします。close()
各スレッドがソケットのメソッドも使用するという事実がなければ (たとえば、ソケットが「シャットダウン」コマンドを受け取ったとき)、作業中のコードをすでに再構築していたでしょう。私が知る限り、これらのスレッドの主な目的は、送信または処理のためにメッセージをキューに入れることです。そのため、単一責任の原則に違反している可能性があり、これらのスレッドはソケットを閉じることができないはずです (分離されたモデム インターフェイスと比較してください)。)? しかし、あまりにも長い間コードを分析し続けると、一般的に設計に欠陥があり、全体を書き直す必要があるように見えます。経営陣が代償を払っても構わないと思っていたとしても、レガシー コードを真剣にリファクタリングし、単体テストをまったく行わず、デバッグが困難な同時実行性の問題に対処することは、おそらく有益よりも害を及ぼすでしょう。そうじゃない?