我正在使用一个对象,它主要用作字符串映射的包装器:
public class Wrapper {
private Map<String, String> values;
private Formatter formatter;
public BigDecimal getSpecialValue() {
String result = values.get("Special");
return formatter.formatNumber(result);
}
}
上述格式化程序大致用作SimpleDateFormat
的映射器 public class Formatter {
private static final NumberFormat NUMBER_FORMAT;
public BigDecimal formatNumber(String s) {
Number num = NUMBER_FORMAT.parse(s);
if (num instanceof Integer) {
return new BigDecimal((Integer) num);
} else if (num instanceof Double) {
return new BigDecimal((Double) num);
} ...
}
}
当我一次通过多个线程访问getSpecialValue()
方法时,一些行为准确,只能通过并发访问来解释,例如可能有NumberFormatException
或{{1}其中解析后的字符串是.430.430而不是.430,依此类推。
有两个方面引起我的兴趣:
1.)包装器只能以只读方式访问。虽然对该集合的访问不同步,但我认为这应该始终有效。
2.)在第一次发现问题的尝试之一中,我更改了ParseException
类的构造函数以执行Wrapper
方法(显然是单线程),这消除了执行时的所有异常。
有人可以解释一下吗?
编辑:
formatNumber
类中的映射填充在构造函数中,最明确的是单线程。然后设计包装器使得映射是不可变的。
答案 0 :(得分:9)
只需在jdoc中搜索“thread”就可以找到NumberFormat类的以下内容:Number formats are generally not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.
答案 1 :(得分:1)
NumberFormat不是线程安全的。因此将其存储在静态变量中并从多个线程中使用它将导致问题。可以同步此对象的每次使用,也可以将其存储在ThreadLocal变量中。
即使只能以只读方式访问包装器,也必须有一段时间初始化和填充值映射,以及创建格式化程序的位置,否则就不会有任何格式化。您没有显示该类的真实完整代码,因此您在此类中也可能至少存在可见性问题。