将parse()与Java SimpleDataFormat一起使用时的线程安全性

将parse()与Java SimpleDataFormat一起使用时的线程安全性,java,thread-safety,simpledateformat,Java,Thread Safety,Simpledateformat,我尽力研究源代码,找出SimpleDataFormat中parse()的线程安全性不高的原因。但我仍然不知道在何处销毁竞争条件SimpleDataFormat使用DateFormat的日历字段来存储正在解析的当前日期。该字段周围没有同步,因此并行使用同一SimpleDataFormat对象可能会并行更改日历值,从而导致结果混乱 PS-I仔细阅读了以下源代码: YMMV.如果我正确理解了您的问题,您可以使用threadlocale package aminur.test.formatters;

我尽力研究源代码,找出SimpleDataFormat中parse()的线程安全性不高的原因。但我仍然不知道在何处销毁竞争条件

SimpleDataFormat使用DateFormat的
日历
字段来存储正在解析的当前日期。该字段周围没有同步,因此并行使用同一SimpleDataFormat对象可能会并行更改
日历
值,从而导致结果混乱

PS-I仔细阅读了以下源代码:


YMMV.

如果我正确理解了您的问题,您可以使用threadlocale

package aminur.test.formatters;  

import java.text.DecimalFormat;  
import java.text.DecimalFormatSymbols;  
import java.text.ParseException;  

public class ThreadSafePriceFormatter {  
  // the price formats  
  private static final ThreadLocal<DecimalFormat> pointSeparatedFormat = new         ThreadLocal<DecimalFormat>() {  
    @Override  
    protected DecimalFormat initialValue() {  
        DecimalFormatSymbols symbols = new DecimalFormatSymbols();  
        symbols.setDecimalSeparator('.');  
        return (new DecimalFormat("#0.00", symbols));  
    }  
};  
private ThreadSafePriceFormatter() {  
}  
public static String formatPointSeparated(double price) {  
    return pointSeparatedFormat.get().format(price);  
}  
public static Number parsePointSeparated(String price)  
        throws ParseException {  
    return pointSeparatedFormat.get().parse(price);  
 }  
}  
包aminur.test.formatters;
导入java.text.DecimalFormat;
导入java.text.DecimalFormatSymbols;
导入java.text.ParseException;
公共类ThreadSafePriceFormatter{
//价格格式
私有静态最终ThreadLocal pointSeparatedFormat=new ThreadLocal(){
@凌驾
受保护的DecimalFormat initialValue(){
DecimalFormatSymbols符号=新的DecimalFormatSymbols();
符号。设置小数分隔符('.');
返回(新的十进制格式(“0.00”,符号));
}  
};  
私有ThreadSafePriceFormatter(){
}  
公共静态字符串formatPointSeparated(双倍价格){
返回点separatedFormat.get().format(价格);
}  
公共静态编号parsePointSeparated(字符串价格)
抛出异常{
返回点separatedFormat.get().parse(价格);
}  
}  

从此

为避免竞争条件,每次创建新的
SimpleDataFormat
,并仅共享格式字符串:

private static final String DATE_FORMAT = "...";

private void foo() {
    SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT);
    ...
}

如果(且仅当)性能出现问题,您可以为每个线程创建一个
SimpleDateFormat
实例。但通常,每次需要使用时都可以创建一个新实例。

SimpleDataFormat还在其解析方法中使用
compiledPattern
,该方法定义为:

transient private char[] compiledPattern;

要添加到您的答案中—“在解析之前,将清除日历的所有日期时间字段,并且日历的日期时间字段的默认值将用于任何缺少的日期时间信息。”—请检查此链接。日历字段不再是DateFormat的成员。作为掌握并发编程的智力练习,您是否感兴趣?或者在你的约会时间工作中寻找一个实用的解决方案?