スレッドセーフ

直接並行処理を実装してないから関係ないとは限らない。スレッドセーフを意識することは必要。

概要

スレッドセーフとは、おおよそ次のような定義。

複数のスレッドからアクセスされたときに実行のタイミングがどうであっても、呼び出し側に同期化の努力が必要なく正しく振る舞えるクラスのこと。

— 「Java並行処理プログラミング」 P.20

スレッドセーフを考えるときに一番問題なのは、オブジェクトのステート(フィールド)へのアクセス。複数のスレッドによる無秩序なアクセスがあっても、正しい状態を維持し続けられるようにクラスを作ることがすなわち、スレッドセーフなクラスを作成することになる。

自らスレッドを生成していなくてもサーブレットやGUIのようにそもそもプラットフォームの前提がマルスレッドであったり、パフォーマンスが悪くて後からマルチスレッドにしようと思うこともあるのでスレッドセーフなクラスを作成したり判断したりできることは重要。

スレッドセーフの例

ローカル変数

実行中のスレッドのローカル変数は、他のスレッドからアクセスする方法がないのでスレッドセーフになる。よってスレッドセーフを考えるとき、ローカル変数は外してよい。フィールドの方を気にする。

ステートレス

フィールド(ステート)を持たなければ、スレッド間で共有されるモノもないので当然スレッドセーフ。

一番身近な例が「サーブレット」。サーブレットのポリシーに従う限りにおいては、サーブレット自体にフィールドを持たない(ステートレス)。このためリクエストのたびにスレッドが生成されるサーブレットであってもスレッドセーフとなる。

固定(変更不可能)なオブジェクト

例えばコンストラクション時に初期化され、finalなフィールドは固定(変更不可能)なオブジェクトになる。read onlyでいつでも同じ値を返し続けるのでスレッドセーフ。

ただしフィールドの保持する先オブジェクトのフィールドまでは固定されないので、そこは保証できない。