JavaマルチスレッドプログラミングでDateFormatクラスを使用

3154 ワード

DateFormatクラスはスレッド以外で安全なクラスです.JAvadocsドキュメントでは、「Date formatsは同期できません.スレッドごとに独立した日付フォーマットを作成することをお勧めします.複数のスレッドが同時に1つの日付フォーマットにアクセスする場合は、外部に同期コードブロックを追加する必要があります」と説明しています.
次のコードでは、スレッド環境でDateFormatを使用して文字列の日付を日付オブジェクトに変換する方法を示します.ローカル言語と国を複数回取得する必要がないため、日付フォーマットを取得するインスタンスを作成すると効率的です. 

public class DateFormatTest {
 
 private final DateFormat format =
      new SimpleDateFormat("yyyyMMdd");
 
 public Date convert(String source)
           throws ParseException{
  Date d = format.parse(source);
  return d;
 }
}

このコードは非スレッドで安全です.複数のスレッドで呼び出すことができます.次の呼び出しコードで、2つのスレッドを持つスレッドプールを作成し、5つの日付変換タスクをコミットした後、実行結果を表示します.

final DateFormatTest t =new DateFormatTest();
Callable task =new Callable(){
  public Date call()throws Exception {
    return t.convert("20100811");
  }
};
 
//     2      
ExecutorService exec = Executors.newFixedThreadPool(2);
List> results =
       new ArrayList>();
 
//  5     
for(int i =0; i <5; i++){
  results.add(exec.submit(task));
}
exec.shutdown();
 
//    
for(Future result : results){
  System.out.println(result.get());
}

コードの実行結果は私たちの望み通りではありません.場合によっては、正しい日付を出力したり、エラーを出力したり(例えば.Sat Jul 31 00:00:00:00 BST 2012)、NumberFormatExceptionを放出したりすることもあります.
DateFormatクラスの同時使用方法
スレッドが安全な場合にDateFormatクラスを使用する方法はいくつかあります.
1.同期
最も簡単な方法は、日付変換を行う前にDateFormatオブジェクトにロックをかけることです.この方法では、DateFormatオブジェクトに一度に1つのスレッドしかアクセスできず、他のスレッドは待つしかありません. 

public Date convert(String source)
          throws ParseException{
 synchronized(format) {
  Date d = format.parse(source);
  return d;
 }
}

2.ThreadLocalを使う
もう1つの方法は、ThreadLocal変数を使用してDateFormatオブジェクトを収容することです.つまり、各スレッドには独自のコピーがあり、他のスレッドが解放されるのを待つ必要はありません.この方法は同期ブロックを使用するよりも効率的である. 

public class DateFormatTest {
 
 private static final ThreadLocal df
         = new ThreadLocal(){
  @Override
  protected DateFormat initialValue() {
    return new SimpleDateFormat("yyyyMMdd");
  }
 };
 
 public Date convert(String source)
           throws ParseException{
  Date d = df.get().parse(source);
  return d;
 }
}

3. Joda-Time
Joda-timeは素晴らしいオープンソースJDKの日付とカレンダーAPIの代替品で、DateTimeFormatはスレッドが安全で変わらない.
 

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import java.util.Date;
 
public class DateFormatTest {
 
 private final DateTimeFormatter fmt =
    DateTimeFormat.forPattern("yyyyMMdd");
 
 public Date convert(String source){
  DateTime d = fmt.parseDateTime(source);
  returnd.toDate();
 }
}