简体   繁体   English

SimpleDateFormat.clone()是线程安全的吗?

[英]Is SimpleDateFormat.clone() thread-safe?

I'm looking at legacy code and found the following: 我正在查看旧版代码,发现以下内容:

private static final SimpleDateFormat sdf = new SimpleDateFormat("...");
...
void foo() {
    bar(date, someMoreArgs, sdf.clone());
}

where bar() then goes ahead and uses the passed SimpleDateFormat to format the given date. 然后bar()继续,并使用传递的SimpleDateFormat格式化给定的日期。

Is the above code thread-safe? 上面的代码是线程安全的吗? If multiple threads concurrently call sdf.clone() , can one of the cloned objects end up getting corrupted? 如果多个线程同时调用sdf.clone() ,那么克隆对象之一是否最终会损坏?

I wouldn't write the code like that myself in the first place. 首先,我不会自己写这样的代码。 I know there are better ways to do this. 我知道有更好的方法可以做到这一点。 But I'm not looking to refactor the code unless it can be proven to be not thread-safe. 但是我不希望重构代码,除非可以证明它不是线程安全的。

Edit: 编辑:
Some more information for clarification: 一些更多信息需要澄清:

  1. The static object sdf itself is never used for formatting. 静态对象sdf本身从不用于格式化。 The only operation it's ever used for is cloning. 它曾经用于的唯一操作是克隆。 Thus, I'm not expecting its contents to change (unless the cloning operation writes some transient data inside the object). 因此,我并不期望其内容发生变化(除非克隆操作在对象内部写入了一些临时数据)。

  2. The clone is never used by more than one thread. 该克隆永远不会被多个线程使用。

From the JavaDoc: 从JavaDoc:

Date formats are 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. 如果多个线程同时访问一种格式,则必须在外部进行同步。

So I believe that it depends on how you use that clone, but it is not assured. 因此,我相信这取决于您如何使用该克隆,但是不能保证。 Cloning does not make your classes thread-safe. 克隆不会使您的类成为线程安全的。 If the cloned object is not shared between class instances it should work with no problems, but I would not recommend this approach. 如果克隆的对象不在类实例之间共享,则它应该可以正常工作,但是我不推荐这种方法。 However, you need a thread-safe date formatter I would suggest using Apache Commons FastDateFormat, described here . 然而,你需要一个线程安全的日期格式,我建议使用Apache下议院FastDateFormat,描述在这里

Basically the clone() method doesn't give you thread safety. 基本上,clone()方法不会为您提供线程安全。 It just copies the properties of one object to another one. 它只是将一个对象的属性复制到另一个对象。 It doesn't lock or synchronize that object so if it is thread safe or not is up to the implementation. 它不会锁定或同步该对象,因此它是否是线程安全的取决于实现。 If during that copy some of the properties of the original object are changed then you might get into a strange state. 如果在该复制期间更改了原始对象的某些属性,则您可能会陷入一种奇怪的状态。 If you use that cloned object in more than one threads - you still got problems 如果您在多个线程中使用该克隆对象-您仍然会遇到问题

For your particular example I think the code is fine. 对于您的特定示例,我认为代码很好。 The sdf object you are going to clone is probably never gonna change and you don't need a lock or something (it seems). 您将要克隆的sdf对象可能永远都不会改变,并且您不需要锁或其他东西(看起来)。 You just create a new SimpleDateFormat object for each thread to ensure thread safety - or at least that's the idea - and you achieve that by using clone. 您只需为每个线程创建一个新的SimpleDateFormat对象以确保线程安全-或至少就是这个主意-并通过使用clone来实现。

Anyway if you have spotted a problem in legacy code and you don't like it it is always better to spend some time and refactor it than to keep it like that even if you don't like it. 无论如何,如果您发现了遗留代码中的问题,并且您不喜欢它,那么总要花一些时间和重构它,而不是像这样使它保持不变,即使您不喜欢它也总是更好。 It almost always pays off in the long term with having better and more maintainable code and not leaving that like that for the next developer to wander. 从长远来看,通过拥有更好,更可维护的代码,并且几乎不让下一个开发人员流连忘返,它几乎总是有回报的。 For example if you have upgraded to java 8 you can use DateTimeFormatter which is thread safe or you can use some external library. 例如,如果您已升级到Java 8,则可以使用线程安全的DateTimeFormatter或使用某些外部库。 Or at least create a new SimpleDateFormat(SOME_CONSTANT_FORMAT) everytime you need one instead of relying on clone of the object - because if you share just a string constant (the actual format) it is immutable and thread safe. 或者至少每次需要一个新的SimpleDateFormat(SOME_CONSTANT_FORMAT)而不是依赖于对象的克隆-因为如果仅共享一个字符串常量(实际格式),则它是不可变的,并且是线程安全的。

This is not an answer. 这不是答案。 But some information you may still find interesting. 但是您可能仍然会发现一些有趣的信息。 I did a couple of experiments. 我做了几个实验。

First I had two threads formatting dates using the same SimpleDateFormat instance. 首先,我有两个线程使用相同的SimpleDateFormat实例格式化日期。 After a couple of iterations they began giving incorrect results, and after a few hundred iterations one of the threads crashed. 经过几次迭代后,他们开始给出错误的结果,经过几百次迭代,其中一个线程崩溃了。 So the thread-unsafety seems very real. 因此,线程不安全性看起来非常真实。

Next I had one thread format dates using the original SimpleDateFormat and the other one taking clones of it and using the clones for formatting. 接下来,我有一个使用原始SimpleDateFormat线程格式日期,另一个使用了它的克隆并使用克隆进行格式化。 Both threads have run for several minutes now and are still both producing correct results. 这两个线程现在已经运行了几分钟,仍然都可以产生正确的结果。

This is by no means any guarantee that this is the behaviour you will always see. 这绝不能保证您将始终看到这种行为。 The documentation is pretty clear: SimpleDateFormat is not thread safe and all access from several threads must be synchronized. 该文档非常清楚: SimpleDateFormat不是线程安全的,必须同步来自多个线程的所有访问。 So use the information at your own risk. 因此,使用这些信息需要您自担风险。

EDIT: Inspecting the source code seems to reveal that the clone operation copies fields in some order, but doesn't modify the original. 编辑:检查源代码似乎表明克隆操作以某种顺序复制字段,但不修改原始字段。 If the original was doing any work in another thread, this might cause the clone to be in an inconsistent state after creation, which in turn might or might not affect its correct working. 如果原始文件正在另一个线程中执行任何工作,则可能导致克隆在创建后处于不一致状态,这反过来可能会或可能不会影响其正确工作。 If the original is only used for cloning, I see no risk with the current implementation. 如果原始文件仅用于克隆,那么我认为当前的实现没有任何风险。 As you say, the implementation may be changed in later Java versions, but I would consider the risk small, and the risk of thread-unsafe behaviour being introduced even smaller. 如您所说,在更高的Java版本中可能会更改实现,但是我认为风险很小,而引入线程不安全行为的风险则更小。 All of this is pure speculation! 所有这些纯属猜测!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM