[Java] 多线程环境下使用 DateFormat 已翻译 100%

oschina 投递于 2013/01/17 07:23 (共 4 段, 翻译完成于 01-17)
阅读 13223
收藏 145
16
加载中

DateFormat 类是一个非线程安全的类。javadocs 文档里面提到"Date formats是不能同步的。 我们建议为每个线程创建独立的日期格式。 如果多个线程同时访问一个日期格式,这需要在外部加上同步代码块。"

以下的代码为我们展示了如何在一个线程环境里面使用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;
  }
}
这段代码是非线程安全的。我们可以通过在多个线程中调用它。在以下调用的代码中,我创建了一个有两个线程的线程池,并提交了5个日期转换任务,之后查看运行结果:
final DateFormatTest t =new DateFormatTest();
Callable<Date> task =new Callable<Date>(){
    public Date call()throws Exception {
        return t.convert("20100811");
    }
};
 
//让我们尝试2个线程的情况
ExecutorService exec = Executors.newFixedThreadPool(2);
List<Future<Date>> results =
             new ArrayList<Future<Date>>();
 
//实现5次日期转换
for(int i =0; i <5; i++){
    results.add(exec.submit(task));
}
exec.shutdown();
 
//查看结果
for(Future<Date> result : results){
    System.out.println(result.get());
}
代码的运行结果并非如我们所愿 - 有时候,它输出正确的日期,有时候会输出错误的(例如.Sat Jul 31 00:00:00 BST 2012),有些时候甚至会抛出NumberFormatException!
enixyu
enixyu
翻译于 2013/01/17 08:58
8

如何并发使用DateFormat类

我们可以有多种方法在线程安全的情况下使用DateFormat类。

1. 同步

最简单的方法就是在做日期转换之前,为DateFormat对象加锁。这种方法使得一次只能让一个线程访问DateFormat对象,而其他线程只能等待。

public Date convert(String source)
                    throws ParseException{
  synchronized(format) {
    Date d = format.parse(source);
    return d;
  }
}
enixyu
enixyu
翻译于 2013/01/17 09:03
5

2. 使用ThreadLocal

另外一个方法就是使用ThreadLocal变量去容纳DateFormat对象,也就是说每个线程都有一个属于自己的副本,并无需等待其他线程去释放它。这种方法会比使用同步块更高效。

public class DateFormatTest {
 
  private static final ThreadLocal<DateFormat> df
                 = new ThreadLocal<DateFormat>(){
    @Override
    protected DateFormat initialValue() {
        return new SimpleDateFormat("yyyyMMdd");
    }
  };
 
  public Date convert(String source)
                     throws ParseException{
    Date d = df.get().parse(source);
    return d;
  }
}
enixyu
enixyu
翻译于 2013/01/17 09:08
8
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();
  }
}


红薯
红薯
翻译于 2013/01/17 08:50
9
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(20)

JoeyBlue
JoeyBlue
@enixyu 翻译的很不错 顶一个
不过个人以为 第一段 中 "Date formats是不能同步的。 我们建议为每个线程创建独立的日期格式。 如果多个线程同时访问一个日期格式,这需要在外部加上同步代码块。" 里出现的两个“日期格式” 不翻译 直接写成DateFormat 可能更好懂些
ayesd
ayesd
nice!
Howard.L.Huang
Howard.L.Huang
org.apache.commons.lang3.time.DateFormatUtils
public class DateFormatUtils
extends Object
Date and time formatting utilities and constants.

Formatting is performed using the thread-safe FastDateFormat class.
优雅先生
优雅先生

引用来自“别侥幸别尝试”的评论

引用来自“jxqlovejava”的评论

引用来自“车开源”的评论

我也终于找到“收藏”了,激动!!

Ctrl+F,收藏

什么浏览器是这个快捷键?

Ctrl+F搜索“收藏”这个词,o(╯□╰)o
嘉树
嘉树

引用来自“jxqlovejava”的评论

引用来自“车开源”的评论

我也终于找到“收藏”了,激动!!

Ctrl+F,收藏

什么浏览器是这个快捷键?
yizhichao
yizhichao
非常感谢,收藏了。
优雅先生
优雅先生

引用来自“车开源”的评论

我也终于找到“收藏”了,激动!!

Ctrl+F,收藏
优雅先生
优雅先生
我觉得还有1种简单的解决方法,即使用临时变量。这样耗费的内存可能大些,但是效率却可能比使用对象互斥锁快。以空间换时间的思想。
public Date convert(String source) throws ParseException{
DateFormat format = new SimpleDateFormat("yyyyMMdd");
Date d = format.parse(source);
return d;
}
10000011
10000011
. Joda-Time 很不错!
车开源
车开源
我也终于找到“收藏”了,激动!!
返回顶部
顶部