Java SimpleDataFormat的线程安全问题

Java SimpleDataFormat的线程安全问题,java,thread-safety,simpledateformat,Java,Thread Safety,Simpledateformat,我从一个程序员测试中得到了以下代码 private String formatDate(Date date) { String result = ""; //…. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); result = sdf.format(date); //… return result; } 附加的信息是多个线程同时使用该方法。这有什么问题吗 我的回答是不,应该没问题(假设//…部分中没

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

private String formatDate(Date date)
{
  String result = "";
  //….
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  result = sdf.format(date);
  //…
  return result;
}
附加的信息是多个线程同时使用该方法。这有什么问题吗

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

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

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


那么,我的答案或解决方案正确吗?

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

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

正确答案不正确。然而,传入的
日期也不安全,因为它是从外部接收的,因此可能会出现数据竞争问题。
SimpleDataFormat
是一个真正的麻烦,因为它是一个)线程不安全;b) 初始化速度慢。必须缓存线程本地实例,这是最糟糕的选项。@MarkoTopolnik IMHO“Slow”在这个上下文中是一个被过度使用的术语。只要您没有遇到性能问题,我总是更喜欢方法本地对象的简单性,而不是使用ThreadLocal,这对许多人来说仍然是一本封闭的书developers@Korgen
SimpleDateFormat
s设计对性能的影响限制了它的用例。这并不意味着这个类的每一次使用都会有性能问题。我仍然不明白为什么他们不在SimpleDataFormat内部使用ThreadLocal,这样我们就不必这样做了。这将符合性能约束,并且类将是线程安全的。如果同一日期对象在修改它的多个线程之间共享,并且其访问不同步,那么使用Date.getTime()将不足以消除所有问题。它将减少机会窗口,但不会完全消除机会窗口,因为在调用Date.getTime()之前,日期对象的值仍可能被另一个线程更改。如果在线程之间共享同一个Date对象存在一些问题,那么应该同步对此对象的访问,并改用Date.getTime()来解决此问题。使用
long
type将在多线程环境中保存方法的约定。如果改为使用
Date
类型,则方法的一部分可以与一个
Date
实例一起执行,方法的另一部分可以与另一个
Date
实例一起执行。这种情况将破坏该方法的契约。此外,我们不知道asker将如何使用
Date
实例,也无法提出如何正确同步访问。根据他接受的答案,他根本不需要在
日期
实例上进行任何同步。不需要遵守任何合同,因为日期的值存储在私有日历对象中:“calendar.setTime(Date);”;因此,方法“sdf.format(date)”的所有部分都在相同的日期值上执行,即使此日期对象同时被另一个线程更改。在多线程竞争条件下,可能会返回错误的值,但该值不会损坏(如果这样说有意义的话)。我不是舒尔关于
/…
部分的。例如,这一部分可能会影响一些有价值的东西,而不是本地的东西。但是如果没有什么有价值的东西,那么从我的观点来看,你是正确的。为了完整起见,我应该提到我指的是“受保护的日历”对象,它是DateFormat和SimpleDateFormat类的一部分;与负责其非线程安全的对象完全相同。如果我们将
SimpleDateFormat
声明为实例变量,那么我们可以使用
synchronized block
使其线程安全,对吗?但声纳显示警告。有没有办法解决声纳问题?