【问题标题】:Date Conversion with ThreadLocal使用 ThreadLocal 进行日期转换
【发布时间】:2013-09-06 13:15:36
【问题描述】:

我需要将传入的日期字符串格式“20130212”(YYYYMMDD) 转换为 12/02/2013 (DD/MM/YYYY)

使用ThreadLocal。我知道没有ThreadLocal 的方法。谁能帮帮我?

没有ThreadLocal的转化:

    final SimpleDateFormat format2 = new SimpleDateFormat("MM/dd/yyyy");
    final SimpleDateFormat format1 = new SimpleDateFormat("yyyyMMdd");
    final Date date = format1.parse(tradeDate);
    final Date formattedDate = format2.parse(format2.format(date));

【问题讨论】:

  • 为什么需要使用 ThreadLocal?
  • 因为 SimpleDateFormats(以及实际上大多数其他 Format 实例)不是线程安全的。有关此主题,请参阅我的 blog post

标签: java simpledateformat date-conversion


【解决方案1】:

这背后的想法是 SimpleDateFormat 不是线程安全的,因此在多线程应用程序中,您不能在多个线程之间共享 SimpleDateFormat 的实例。但是由于创建 SimpleDateFormat 是一项昂贵的操作,我们可以使用 ThreadLocal 作为解决方法

static ThreadLocal<SimpleDateFormat> format1 = new ThreadLocal<SimpleDateFormat>() {
    @Override
    protected SimpleDateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd");
    }
};

public String formatDate(Date date) {
    return format1.get().format(date);
}

【讨论】:

  • 人们会这样做吗?如果您(最初的 l 海报)不正确理解 ThreadLocals,我建议您不要使用它们。我可能会考虑 Commons Lang 的 FastDateFormat 或 JodaTime 库的 DateTimeFormat。这是一个关于这个主题的长而有趣的线程.. jsr166-concurrency.10961.n7.nabble.com/…
  • @JohnMark13 :是的,人们会这样做。我也recommend它。他怎么不正确理解 ThreadLocals? 《Effective Java》的作者 Joshua Bloch 在您的链接上说:“这个线程充满了错误信息。[..] 线程局部变量本质上没有任何问题:它们不会导致内存泄漏。它们并不慢。”。讨论是关于 Tomcat 和其他一些使用线程池的应用程序中的错误,并且在 ThreadLocals 方面存在实现问题。它们可以而且应该在这些应用中得到修复。
  • @StijndeWitt 因为他的问题是[释义]“我不知道如何使用 Thread Local 来做到这一点”。另请参阅,“否则它会泄漏内存。为什么在当前线程工作完成后我们想要这些引用”,这表明缺乏理解。同意应该固定在容器中,但您首先需要了解它们是什么,其次它们可能如何影响您的项目是您错误地使用它们。或者,只需从 SO 中复制一个代码 sn-p 即可,不必担心理解它的作用。
  • 是的......我对这个答案的评论而不是问题本身的评论感到困惑,但你是对的......只有在你了解它会产生的影响时才使用它。
【解决方案2】:

除了编写不可变类之外,Java 中的ThreadLocal 是一种实现线程安全的方法。由于 SimpleDateFormat 不是线程安全的,您可以使用 ThreadLocal 使其成为线程安全的。

class DateFormatter{

    private static ThreadLocal<SimpleDateFormat> outDateFormatHolder = new ThreadLocal<SimpleDateFormat>() {
    @Override
    protected SimpleDateFormat initialValue() {
        return new SimpleDateFormat("MM/dd/yyyy");
    }
};

private static ThreadLocal<SimpleDateFormat> inDateFormatHolder = new ThreadLocal<SimpleDateFormat>() {
    @Override
    protected SimpleDateFormat initialValue() {
        return new SimpleDateFormat("yyyyMMdd");
    }
};

public static String formatDate(String date) throws ParseException { 
    return outDateFormatHolder.get().format(
            inDateFormatHolder.get().parse(date));
}        
}

【讨论】:

  • 谢谢 Richie,但是你的类没有工作说类主体,字段声明没有完成。我添加了额外的右括号,但仍然没有运气。还有如何在 calll 结束后删除这些线程本地引用。跨度>
  • 现在检查。我现在已经添加了大括号。
  • 否则会泄漏内存。为什么我们要在当前线程工作完成后进行这些引用。
  • 如果您看到代码 - 两个对象都是静态的,这意味着它就像单例。只要不是每次都创建 ThreadLocal 实例,就不必担心内存泄漏。但如果您非常特别 - 要删除引用,您可以从 formatDate 方法手动调用 outDateFormatHolder.remove() 和 inDateFormatHolder.remove() 。 stackoverflow.com/questions/3869026/…
  • "最终日期日期 = format1.parse(tradeDate); 最终日期 formattedDate = format2.parse(format2.format(date));" - 日期和格式化日期相同 - 可以调试和检查。如果您需要日期对象,那么第一条语句就足够了 - 日期对象不以格式存储。如果您想在第二条语句之后再次打印日期对象,仍然需要调用 format 方法。
猜你喜欢
  • 1970-01-01
  • 2014-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-23
  • 1970-01-01
  • 2015-02-16
相关资源
最近更新 更多