【问题标题】:Simple Date Format简单日期格式
【发布时间】:2012-01-15 14:49:16
【问题描述】:

我在课堂上以下列方式在我的应用程序中使用简单的日期格式:

static SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");

public static myFunction(final String strDate)
{
      Date endDate = null;
 endDate = MyClass.sdf.parse(strDate);
}

我正在使用 FindBugs,它在上面的代码中给出了以下错误:

“正如 JavaDoc 所述,对于多线程使用,DateFormat 本质上是不安全的。检测器发现了对通过静态字段获得的 DateFormat 实例的调用。这看起来很可疑。”

谁能解释一下这个错误。我无法理解上述消息试图说明的内容。

感谢阅读!!

【问题讨论】:

  • 可能duplicate?
  • @Dallas 指出的问题措辞不同,但接受的答案很有用且相当完整。
  • 大多数开发人员都明白,对于大多数非线程安全的类,这是由于同时更改状态所致。建立格式后,格式化日期不应更改状态。仅在官方文档中将其记录为不是线程安全的是不够的。应该明确记录,如果格式方法在实例变量中保持临时状态,则它也不是线程安全的。将其声明为静态不仅仅是一个新手错误。可以在修改集合 (put) 与访问集合 (get) 之间进行类比。

标签: java findbugs simpledateformat


【解决方案1】:

其他回答有关线程安全并从 SimpleDateFormat 之前删除 static 关键字的人是正确的,尽管您随问题发布的代码根本不可编译。

我认为这更接近您要查找的代码:

public static Date parseDateStr(final String dateStr) throws ParseException
{
 SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
 return sdf.parse(dateStr);
}

【讨论】:

  • 另一种方法是将 parseDateStr 声明为同步。
【解决方案2】:

从静态 SimpleDateFormat 中删除静态 sdf = new SimpleDateFormat("MM/dd/yyyy");

var 被保存为一个限定于此方法的静态实例。这意味着同时访问此方法的其他线程将对同一实例进行 dateformat 调用,这不是线程安全的。

【讨论】:

  • 不能使它成为非静态的。实际上它被用于方法是静态的实用程序类中,因此可以使用类名调用。类似于: return MyUtil.sdf.format(calendar.getTime()); -- 任何其他解决方案还是可以忽略 FingBugs ?
  • 如果你的应用是单线程的,那么你可以忽略它。根据您的评论,我假设 sdf 是类字段而不是方法内部。如果是这种情况,您应该更新您的问题。如果您的应用程序是多线程的,那么我建议不要保留 SDF 的静态实例以供这样使用。在这些情况下,它可能会返回不可预测的结果。您可以通过一种方法提供对该字段的同步访问并将该字段设为私有以避免任何人绕过此方法来解决此问题。
【解决方案3】:

DateFormat 不是线程安全的。这甚至记录在javadoc 中。由于您将其声明为 static 变量,FindBugs 知道它有可能在多个线程中使用。阅读有关issue and alternatives here 的更多信息。

此外,您的代码不应编译,因为 Java 不支持本地静态变量。 How do I create a static local variable in Java?

【讨论】:

    【解决方案4】:

    按照Pangea的建议继续,你可以测试下面的代码。

    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    
    
    public class Test {
    
        public static Date myFunction(final String strDate) throws ParseExceptoion
        {
         SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
            return sdf.parse(strDate);
    
        }
    
    
    public static void main(String[] args) throws ParseException {
        System.out.println(myFunction("05/18/1989").toString());
    
    }
    }
    

    【讨论】:

      【解决方案5】:

      我遇到了一个问题,即在 eclipse 之外构建时 JUnit 测试失败(通过 DOS ANT 构建和测试脚本),但它在 eclipse 中运行得很好。

      被测代码是批处理作业中的一个类和方法,其 SimpleDateFormat 声明为私有静态 final。

      我不关心线程安全,因为这个批处理作业是单线程的。

      我也不想在每次需要时都实例化 SimpleDateFormat 的新实例,因为该过程在循环中处理数千个数据行。

      我通过将 SimpleDateFormat 的声明从私有静态最终更改为私有最终瞬态来解决这个问题。

      当然,这确实意味着实例化类,这可能不适用于所有情况,但如果您正在实例化类并且不想每次都创建新实例并且线程安全不是问题,那么这是一个解决方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-19
        • 1970-01-01
        • 1970-01-01
        • 2011-11-05
        • 2013-03-31
        相关资源
        最近更新 更多