つかびーの技術日記

情報系修士卒のWeb系技術日記です。現在のフォーカス分野はアドテクです。

SimpleDateFormatのスレッド安全性(スレッドアンセーフ)を確認する

      2014/12/10

Javaではよく日付の入出力にSimpleDateFormatが利用されると思います。このクラスはスレッドセーフではありません。今日はこれがなぜスレッドセーフではないのかを確かめてみました。

いつものようにサンプルコードを用意します。

これを実行すると今日の日付と1900年の日付が画面上に表示されます。

SimpleDateFormatはスレッドアンセーフですから、タイミングによっては同じ日付が出てしまいます。これを意図的に再現しようと思います。

EclipseでSimpleDateFormatクラスのformat(Date, StringBuffer, FieldDelegate)メソッドにブレークポイントを仕込んでデバッグ実行します。

ここでcalendarメンバ変数に値を格納して、後のステップ(subFormatメソッド)でこれを利用しています。2つのスレッドで同時にメソッドに入った場合、calendar変数が後のスレッドで書き換えられてしまうので、2つのスレッドで同じcalendarを使うことになります。この場合、最終的に画面上には同じ値が2つ表示されます。

前に何度かSimpleDateFormatのスレッド安全性を忘れてコーディングしたことがあるので、これからも気を付けたいです。

じゃあどうすればいいのか(解決策)

SimpleDateFormatを使う部分が常にシングルスレッドであることを保証できないのであれば、素直に都度newしましょう。

上記の場合SimpleDateFormatControlクラスにstaticなSimpleDateFormatがありますが、これは辞めましょう。sdf変数をローカル変数にして、メソッドが呼ばれるたびにnewしましょう。そうすればそのnewしたオブジェクトを共有する事は無いので、スレッドセーフな作りになります。

毎回newしてたら遅いのでは?と思うかもしれませんが、それほど遅くないので安心してください。(そこをnewするコストよりも他の部分の方が圧倒的に遅いはずなので、性能に困ったら他の圧倒的に遅いロジックを何とかしましょう)

 - Java