SimpleDateFormat的线程安全问题以及四种解决办法

1.多线程环境下SimpleDateFormat的不安全问题:

SimpleDateFormat的format方法实际操作的就是Calendar(Calendar变量也就是一个共享变量线程不安全)。

也正是因为每次在转化时间的时候foramat会先把时间set到calendar中,这样就会导致A线程读取到B线程的时间

image
image

我们来试一下:

定义两个全局常量


private static final String myDateStr = "2022-01-01";

private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

//写一个测试方法:

private static void test(Callable task) throws Exception {

    ExecutorService pool = Executors.newFixedThreadPool(10);

    List<Future> list = new ArrayList<>();

    for (int i = 0; i < 10; i++) {

        Future future = pool.submit(task);

        list.add(future);

}

    for (Future future : list) {

        System.out.println(future.get());

}

    pool.shutdown();

}

//开始测试:
public static void main(String[] args) throws Exception {

    test(()->dateFormat.parse(myDateStr));

} 

果然控制台报错!

image

解决办法:

1.每次使用parse直接new一个SimpleDateFormat

public static void main(String[] args) throws Exception {

 test(()->new SimpleDateFormat("yyyy-MM-dd").parse(myDateStr));

} 

打印正常!

2.使用synchronized同步锁
public static void main(String[] args) throws Exception {

test(()->{ synchronized(dateFormat) { return dateFormat.parse(myDateStr);} });

} 

打印正常!

3.使用TreadLocal

private static final ThreadLocal<SimpleDateFormat> df = ThreadLocal.withInitial(() ->new SimpleDateFormat("yyyy-MM-dd"));

public static Date parseToDate(String dateString)  {

    try {

        return df.get().parse(dateString);

    } catch (ParseException e) {

        return null;

}

}

public static void main(String[] args) throws Exception {

test(()->parseToDate(myDateStr));

} 

打印正常!

4.使用java8 DateTimeFormatter线程安全对象
public static void main(String[] args) throws Exception {

test(()->LocalDate.parse(myDateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")));

} 

打印正常!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容