理系学生日記

おまえはいつまで学生気分なのか

SimpleDateFormat がスレッドセーフでない件

Java 1.3 の頃は、スレッドセーフでないことが明示されていなかったのではないか。

日付フォーマットは同期化されません。スレッドごとに別のフォーマットインスタンスを作成することをお勧めします。複数のスレッドがフォーマットに同時にアクセスする場合は、外部的に同期化する必要があります。

Oracle Java Technologies | Oracle

スレッドセーフでないばっかりに、SimpleDateFormat をスレッドで使い回すようにすると、全く意味不明な例外が吐かれる。ほんとうにおそろしい。

import java.text.*;
import java.util.*;

public class Main implements Runnable
{
    private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyyMMdd");
    private static Thread thr1;
    private static Thread thr2;

    public static void main(String[] args) {
        thr1 = new Thread(new Main());
        thr2 = new Thread(new Main());

        thr1.start();
        thr2.start();
    }

    public void run()
    {
        String str = "20100502";
        try {
            while(true)
                SDF.parse(str);
        } catch ( Exception e ) {
            e.printStackTrace();
        }
    }
}
[kiririmode@mbp(job:0)]% java Main
java.lang.NumberFormatException: multiple points
        at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1084)
        at java.lang.Double.parseDouble(Double.java:510)
        at java.text.DigitList.getDouble(DigitList.java:151)
        at java.text.DecimalFormat.parse(DecimalFormat.java:1303)
        at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1589)
        at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1312)
        at java.text.DateFormat.parse(DateFormat.java:335)
        at Main.run(Main.java:24)
        at java.lang.Thread.run(Thread.java:637)

追記

代替としては、Apache Jakarta Commons Lang の FastDateFormat でも使えば良いと思います。