DateFormat 线程安全

 

SimpleDateformat 线程不安全

SimpleDateFormat 继承自 DateFormat, SimpleDateFormat中的parse方法override父类DateFormat的parse方法。DateFormat的父类提供了public setCalendar的方法 导致潜在的线程安全问题。

  • parse方法不安全,使用了实例变量calendar.  当SimpleDateFormat设置为静态变量,多线程calendar发生变化,造成parse中的calendar变量发生了修改。

  • format方法不安全,同样是calendar引起的。

 

 

解决方案一 jdk7 ThreadLocal

public class MyDateUtil {

    private static final ThreadLocal<DateFormat> threadSafeFormat = new ThreadLocal<DateFormat>();
    private static final String MESSAGE_FORMAT = "MM-dd HH:mm:ss.ms";

    public static final DateFormat getDateFormat() {
        // 并发环境下,获取到的是本线程内自己的format
        DateFormat format = threadSafeFormat.get();
        if (format == null) {
            format = new SimpleDateFormat(MESSAGE_FORMAT);
            // 并发环境下,将format设置到自己的线程内
            threadSafeFormat.set(format);
        }

        return format;
    }
}

 

解决方案二 jdk7 每次new一个新对象

public static final Date getDate(String formatter, String date) {
    DateTimeFormatter formatter = new DateTimeFormatter(formatter);
    return formatter.format(date);
}

 

 

 解决方案二 jdk8  DateTimeFormatter 线程安全

 DateTimeFormatter内部的static methods 都是返回 new对象或者

    public static Date convertStr2Date(String strDate, String dateFormatter, ZoneIdEnum timezone) {
        DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern(dateFormatter);
        LocalDate parseDate = LocalDate.parse(strDate,ofPattern);
        ZoneId zone = ZoneId.of(timezone.getZoneId());
        Instant instant = parseDate.atStartOfDay().atZone(zone).toInstant();
        return Date.from(instant);
    }

 

public enum ZoneIdEnum {
    AUSTRALIA_DARWIN("Australia/Darwin"), 
    AUSTRALIA_SYDNEY("Australia/Sydney"),
    AMERICA_ARGENTINA_BUENOS_AIRES("America/Argentina/Buenos_Aires"),
    AFRICA_CAIRO("Africa/Cairo"),
    AMERICA_ANCHORAGE("America/Anchorage"),
    AMERICA_SAO_PAULO("America/Sao_Paulo"),
    ASIA_DHAKA("Asia/Dhaka"),
    AFRICA_HARARE("Africa/Harare"),
    AMERICA_ST_JOHNS("America/St_Johns"),
    AMERICA_CHICAGO("America/Chicago"),
    /**
     * UTC+8
     */
    ASIA_SHANGHAI("Asia/Shanghai"), 
    AFRICA_ADDIS_ABABA("Africa/Addis_Ababa"),
    EUROPE_PARIS("Europe/Paris"),
    AMERICA_INDIANA_INDIANAPOLIS("America/Indiana/Indianapolis"),
    ASIA_KOLKATA("Asia/Kolkata"),
    ASIA_TOKYO("Asia/Tokyo"),
    PACIFIC_APIA("Pacific/Apia"),
    ASIA_YEREVAN("Asia/Yerevan"),
    PACIFIC_AUCKLAND("Pacific/Auckland"),
    ASIA_KARACHI("Asia/Karachi"),
    AMERICA_PHOENIX("America/Phoenix"),
    AMERICA_PUERTO_RICO("America/Puerto_Rico"),
    AMERICA_LOS_ANGELES("America/Los_Angeles"),
    PACIFIC_GUADALCANAL("Pacific/Guadalcanal"),
    ASIA_HO_CHI_MINH("Asia/Ho_Chi_Minh");

    private final String zoneId;
    
    private ZoneIdEnum(String zoneId) {
        this.zoneId = zoneId ;
    }

    public String getZoneId() {
        return zoneId;
    }
}

 

posted @ 2019-03-26 11:07  webglcn  阅读(530)  评论(0编辑  收藏  举报