【问题标题】:Thread safety issue with SimpleDateFormatSimpleDateFormat 的线程安全问题
【发布时间】:2012-11-16 09:54:54
【问题描述】:

我从程序员测试中得到以下代码

private String formatDate(Date date)
{
  String result = "";
  //….
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  result = sdf.format(date);
  //…
  return result;
}

带有多个线程同时使用该方法的附加信息。这有什么问题吗?

我的回答是不,应该没问题(假设 //... 部分没有其他事情发生)。

我的动机是不使用全局或类数据结构。日期作为参数从每个踏板传递,在方法内部仅使用局部变量和局部对象。因此,每个线程都将获取并使用它自己的 SimpleDateFormat 类的对象实例。

但是,这不是测试中的“正确”答案。 “正确”的答案是 SimpleDateFormat 类不是线程安全的,因此需要同步对该对象的访问。

那么,我或解决方案是否正确?

【问题讨论】:

  • “正确”的答案不正确。然而,传入的Date不安全,并且由于它是从外部接收的,因此可能会出现数据争用问题。
  • SimpleDateFormat 是一个真正的猪,因为它是 a) 线程不安全的; b) 初始化缓慢。必须缓存一个线程本地实例,这是最糟糕的选择。
  • @MarkoTopolnik 恕我直言,“慢”在这种情况下是一个被过度使用的术语。只要您不遇到性能问题,我总是更喜欢方法本地对象的简单性,而不是使用 ThreadLocal,这对于许多开发人员来说仍然是一本封闭的书
  • @Korgen SimpleDateFormats 设计对性能的影响限制了它的用例。这并不意味着此类的每次使用都会出现性能问题。
  • 我仍然看不到他们不在 SimpleDateFormat 内部使用 ThreadLocal 的原因,因此我们不必这样做。这将符合性能约束,并且该类将是线程安全的。

标签: java thread-safety simpledateformat


【解决方案1】:

你的答案是正确的。 SimpleDateFormat 不是线程安全的,这是真的,但每个方法调用都会创建一个自己的实例,所以这没关系。如果 SimpleDateFormat 是一个实例变量,那么这将不是线程安全的(正如您所提到的)。

【讨论】:

  • 如果我们将SimpleDateFormat 声明为实例变量,那么我们可以使用synchronized block 使其成为线程安全的,对吧?但声纳显示警告 squid-AS2885 。有什么办法可以解决声纳问题?
【解决方案2】:

SimpleDateFormatter 不是问题 - 这是一个局部变量,不能从多个线程访问它,因为它没有暴露在外部。真正的问题是Date 参数(正如@Marko Topolnik 已经说过的那样)。这个对象可以传递给方法和一些线程,可以在你的formatDate方法执行的中间修改它。您可以使用long 作为参数类型来防止数据竞争。要将Date 转换为long 使用Date.getTime() 方法并从long 创建Date,您可以使用new Date(long) 构造函数。

【讨论】:

  • 如果同一个 Date 对象在多个修改它的线程之间共享并且它的访问不同步,那么使用 Date.getTime() 将不足以消除所有问题。它会减少机会窗口,但不会完全消除它,因为 Date 对象的值仍然可以在 Date.getTime() 被调用之前被另一个线程更改。如果担心在线程之间共享同一个 Date 对象而不是对该对象的访问应该是同步的并且使用 Date.getTime() 而不是解决这个问题
  • 使用long 类型将在多线程环境中保存方法的契约。如果将改用Date 类型,则可以使用一个Date 实例执行方法的一部分,而可以使用另一个Date 实例执行方法的另一部分。这种情况会破坏方法的契约。此外,我们不知道asker 将如何使用Date 实例,也无法提出如何正确同步访问。根据他接受的答案,他根本不需要在 Date 实例上进行任何同步。
  • 不需要遵守任何约定,因为日期的值存储在私有日历对象中:“calendar.setTime(date);”;因此,“sdf.format(date)”方法的所有部分都在相同的日期值上执行,即使此日期对象同时被另一个线程更改。在多线程竞争条件的上下文中,可能会返回错误的值,但该值不会被破坏(如果这样说有意义的话)。
  • 我对@9​​87654338@ 部分不放心。例如,这部分可能会影响有价值而不是本地的东西。但如果没有什么有价值的东西,那么在我看来你是正确的。
  • 为了完整起见,我应该提到我指的是“受保护的日历日历”对象,它是 DateFormat 和 SimpleDateFormat 类的一部分;负责其非线程安全的同一对象。见grepcode.com/file_/repository.grepcode.com/java/root/jdk/…
猜你喜欢
  • 1970-01-01
  • 2013-08-16
  • 2021-12-16
  • 1970-01-01
  • 1970-01-01
  • 2011-11-13
  • 2010-10-08
  • 2012-09-19
  • 1970-01-01
相关资源
最近更新 更多