非线程安全字段不应该是静态的,声纳lint错误

时间:2018-04-27 08:28:34

标签: java instance-variables

嗨,我有这个代码示例。

 public class Util implements Serializable {


        private static final SimpleDateFormat DATE_KEY_FORMAT = new SimpleDateFormat("yyyyMMdd");
        private static final SimpleDateFormat EUS_WS_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
        private static final SimpleDateFormat DATETIME_KEY_FORMAT = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        public static final String TIME_ZONE_GMT = "GMT";


        /**
         * Returns date in the format yyyyMMdd
         * @return
         */
        public static int getyyyyMMdd() {
            return Integer.parseInt(DATE_KEY_FORMAT.format(new Date()));
        }

        public static int getyyyyMMdd(Date date) {
            return Integer.parseInt(DATE_KEY_FORMAT.format(date));
        }

        public static String getyyMMdd(Date dateTime) {
            return DATE_KEY_FORMAT.format(dateTime);
        }

        public static String getyyyyMMddHHmmssSSSCur(Date dateTime) {
            return DATETIME_KEY_FORMAT.format(dateTime);
        }

如果我从行中删除静态:private static final SimpleDateFormat DATE_KEY_FORMAT = new SimpleDateFormat("yyyyMMdd"),那么如何以非静态方式访问它?因为它在下面的代码中显示错误:

public static int getyyyyMMdd() {
        return Integer.parseInt(DATE_KEY_FORMAT.format(new Date()));
    }

除去静电后,任何人都能告诉如何访问它吗?提前谢谢

3 个答案:

答案 0 :(得分:2)

删除static不会使其线程安全:可以同时从不同的线程访问实例。

考虑使用ThreadLocal<SimpleDateFormat>

private static final ThreadLocal<SimpleDateFormat> DATE_KEY_FORMAT =
    ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMdd"));

然后访问静态方法,如下所示:

return Integer.parseInt(DATE_KEY_FORMAT.get().format(new Date()));

因为每个线程都有自己的SimpleDateFormat实例,所以线程之间没有干扰。

但是,变更SimpleDateFormat的变更(例如设置时区)将在给定的主题中保留,直到您调用DATE_KEY_FORMAT.remove()。但如果您从未对此类实例进行更改,则不必担心此事。

答案 1 :(得分:1)

SimpleDateFormat实例不是线程安全的,因此确实不应该具有并发访问权 您应该将静态方法实例方法设为静态方法,不能访问实例成员 另请注意,如果同时访问这些方法,则会出现相同的并发问题。因此,在多线程环境中,您应该在每个方法中创建SimpleDateFormat实例(这可能很昂贵)或者(更便宜)在SimpleDateFormat中添加ThreadLocal的单个实例。

答案 2 :(得分:0)

静态字段属于该类,而实例变量属于该对象。因此,静态字段的值在类的所有实例之间共享。因此,如果您尝试从静态上下文调用实例变量,它将无法工作,因为在调用静态方法时实例可能不存在。

例如,对于某些类,您可以在不实例化实例变量的情况下调用util方法getyyyMMdd()。

    public class SomeClass() {

       public SomeClass(){}

       public printDateInYears() {
           System.out.println(Util.getyyyyMMdd());
       }

    }

访问实例变量的唯一方法是使方法getyyyyMMdd()不是静态的。