【发布时间】:2015-03-19 15:29:56
【问题描述】:
我正在尝试在 Java 中实现日期和数字的格式化程序。但是java中的一些格式化程序不是线程安全的,例如。 DecimalFormat, SimpleDateFormat!(首先,我不明白为什么它们不像DateTimeFormat!)所以,经过一番搜索,我遇到了ThreadLocal 变量。
我见过的所有关于ThreadLocal 的sn-ps,他们都使用final。当然,拥有一个格式化程序实例确实有意义。但是,假设我们需要一个格式化程序,但需要 3 个模式。
FormatFactory.java
public class FormatFactory {
public static ThreadLocal<DecimalFormat> getMoneyFormatter(final String pattern) {
return new ThreadLocal<DecimalFormat>() {
@Override
public DecimalFormat initialValue() {
DecimalFormat decFormat = new DecimalFormat(pattern);
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
symbols.setDecimalSeparator(',');
if (!pattern.equals(FormatPatterns.MT940_DECIMAL)) {
symbols.setGroupingSeparator('.');
}
decFormat.setMinimumFractionDigits(2);
decFormat.setDecimalFormatSymbols(symbols);
return decFormat;
}
};
}
}
Format.java
public static String money(BigDecimal amount, String pattern) {
return FormatFactory.getMoneyFormatter(pattern).get().format(amount);
}
用法
Format.money(balance, FormatPatterns.MT940_DECIMAL)
Format.money(balance, FormatPatterns.SIGNED_MONEY)
Format.money(balance, FormatPatterns.MONEY)
在这种用法中它仍然是线程安全的吗???
更新:
here的答案解决了我的问题。
我的sn-p如下:
private static final ConcurrentMap<String, ThreadLocal<DecimalFormat>> decimialFormatsByPattern = new ConcurrentHashMap<String, ThreadLocal<DecimalFormat>>();
public static DecimalFormat getMoneyFormatter(final String pattern) {
ThreadLocal<DecimalFormat> decimalFormatter = decimialFormatsByPattern.get(pattern);
if (decimalFormatter == null) {
decimalFormatter = new ThreadLocal<DecimalFormat>() {
@Override
public DecimalFormat initialValue() {
DecimalFormat decFormat = new DecimalFormat(pattern);
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
symbols.setDecimalSeparator(',');
if (!pattern.equals(FormatPatterns.MT940_DECIMAL)) {
symbols.setGroupingSeparator('.');
}
decFormat.setMinimumFractionDigits(2);
decFormat.setDecimalFormatSymbols(symbols);
return decFormat;
}
};
decimialFormatsByPattern.putIfAbsent(pattern, decimalFormatter);
}
return decimalFormatter.get();
}
用法
public static String money(BigDecimal amount, String pattern) {
return FormatFactory.getMoneyFormatter(pattern).format(amount);
}
【问题讨论】:
-
Kayaman 说,“……资源泄露。”如果某个线程 t 创建了一个 DecimalFormat 实例(或任何其他对象)并将其粘贴在 ThreadLocal 对象中,则即使在线程 t 死亡后,ThreadLocal 对象仍将继续持有该引用。线程 t 创建的对象永远不会被垃圾回收。当您有一组固定的线程时,ThreadLocal 很适合使用,但它可能会在不断创建新的短期线程的应用程序中导致麻烦。 (注意:一些 ExecutorService 实现会随着请求队列中积压的变化而创建和销毁线程。)
标签: java multithreading static factory thread-local