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

Non-thread-safe fields should not be static, sonar lint error

嗨,我有这个代码示例。

 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()));
    }

任何人都可以告诉我在移除静态后如何访问它吗?提前致谢

SimpleDateFormat 实例不是线程安全的,因此确实不应有并发访问。
您应该使静态方法成为实例方法,因为静态方法无法访问实例成员。
另请注意,如果同时访问这些方法,您将遇到相同的并发问题。因此,在多线程环境中,您应该在每个方法中创建 SimpleDateFormat 实例(这可能很昂贵)或(不太昂贵)在 ThreadLocal.[=14 中添加 SimpleDateFormat 的单个实例=]

删除 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实例,所以线程之间没有干扰。

但是,在您调用 DATE_KEY_FORMAT.remove() 之前,对 SimpleDateFormat 的突变更改(例如设置时区)将保留在给定线程中。但是,如果您从未像那样对实例进行过更改,则无需担心这一点。

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

例如,对于某些 class 你调用 util 方法 getyyyMMdd() 而没有实例化实例变量。

    public class SomeClass() {

       public SomeClass(){}

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

    }

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