美文网首页
02-SimpleDateFormat为什么线程不安全

02-SimpleDateFormat为什么线程不安全

作者: 蜗牛写java | 来源:发表于2020-10-10 23:54 被阅读0次

02-SimpleDateFormat为什么线程不安全

背景

阿里巴巴java开发手册中有这么一条:

【强制】SimpleDateFormat 是线程不安全的类,一般不要定义为static变量,如果定义为 static,必须加锁,或者使用 DateUtils 工具类。

那么今天我们来分析下SimpleDateFormat为什么是线程不安全的;

其实jdk8不再推荐这样使用了,可以使用LocalDate(不可以变类);以下只是感兴趣,探个究竟

错误的例子

先看下错误的例子:

/**
 * @Description SimpleDateFormat 为什么线程不安全
 * @Date 2020/10/10 9:26 PM
 * @Created by dwb
 * 微信: snail_java
 */
public class DateUtils {

    private DateUtils() {}

    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static String formatDate(Date date) {
        return DATE_FORMAT.format(date);
    }

    public static Date parseDateStr(String dateStr) {
        try {
            //为类变异代码阅读,异常在工具方法中try了
            return DATE_FORMAT.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        final String dateStr = "2020-10-10 10:10:10";

        //按照Java规范;线程应该放入线程池中执行;此处为了阅读方便,线程单独执行;
        for (int i = 0; i < 10; i++) {
            Runnable runnable = () -> DateUtils.parseDateStr(dateStr);
            new Thread(runnable).start();
        }

    }
}

运行后

Exception in thread "Thread-5" Exception in thread "Thread-2" Exception in thread "Thread-3" Exception in thread "Thread-1" Exception in thread "Thread-0" Exception in thread "Thread-6" java.lang.NumberFormatException: empty String
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at java.text.DigitList.getDouble(DigitList.java:169)
at java.text.DecimalFormat.parse(DecimalFormat.java:2089)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
at com.dwb.snail.day.day02.DateUtils.parseDateStr(DateUtils.java:28)
at com.dwb.snail.day.day02.DateUtils.lambdamain0(DateUtils.java:40)
at java.lang.Thread.run(Thread.java:748)
java.lang.NumberFormatException: multiple points
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1890)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at java.text.DigitList.getDouble(DigitList.java:169)
at java.text.DecimalFormat.parse(DecimalFormat.java:2089)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
at com.dwb.snail.day.day02.DateUtils.parseDateStr(DateUtils.java:28)
at com.dwb.snail.day.day02.DateUtils.lambdamain0(DateUtils.java:40)
at java.lang.Thread.run(Thread.java:748)

看下源码结构

SimpleDateFormat源码.png

可以看出 SimpleDateFormat 继承 DateFormat;然而DateFormat有两个protected属性(calendar,numberFromat);所以SimpleDateFormat也继承了这两个属性;

因此,多线程情况下,SimpleDateFormat具有两个共享的变量,即calendar(主要存放日期),numberFromat多线程情况下修改共享变量,是线程不安全的

  • parse过程线程不安全分析

    共享变量calendar

    parse中有CalendarBuilder;该builder构建calendar;多线程构建,相当于多个线程同时给属性 set值,所以不安全

  • format过程线程不安全分析

    共享变了calendar

    实际上给calendar设置date,多线程同时set date是不安全的,再调用subFormat将date转换为字符串

如何正确使用SimpleDateFormat

  1. 每次调用时候,创建SimpleDateFormat(不推荐)

    /**
     * @Description 线程安全SimpleDateFormat
     * @Date 2020/10/10 11:42 PM
     * @Created by dwb
     * 微信: snail_java
     */
    public class OK1DateUtils {
    
        private OK1DateUtils() {
        }
    
        public static String formatDate(Date date) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return format.format(date);
        }
    
        public static Date parseDateStr(String dateStr) {
            try {
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                //为类变异代码阅读,异常在工具方法中try了
                return format.parse(dateStr);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    
  1. 使用ThreadLocal (推荐使用)
/**
 * @Description SimpleDateFormat线程安全使用方式
 * @Date 2020/10/10 11:46 PM
 * @Created by dwb
 * 微信: snail_java
 */
public class OK2DateUtils {

    private static final ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() {
        @Override
        protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
    };

    public static String formatDate(Date date) {
        return threadLocal.get().format(date);
    }

    public static Date parseDateStr(String dateStr) {
        try {
            //为类变异代码阅读,异常在工具方法中try了
            return threadLocal.get().parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        final String dateStr = "2020-10-10 10:10:10";

        //按照Java规范;线程应该放入线程池中执行;此处为了阅读方便,线程单独执行;
        for (int i = 0; i < 10; i++) {
            Runnable runnable = () -> OK2DateUtils.parseDateStr(dateStr);
            new Thread(runnable).start();
        }

    }
}

相关文章

  • 02-SimpleDateFormat为什么线程不安全

    02-SimpleDateFormat为什么线程不安全 背景 阿里巴巴java开发手册中有这么一条: 【强制】Si...

  • ThreadLocal可以解决并发问题吗?

    前言 到底什么是线程的不安全?为什么会存在线程的不安全?线程的不安全其实就是多个线程并发的去操作同一共享变量没用做...

  • HashMap问答

    HashMap是不是线程安全? 不是线程安全的。 为什么不安全? 线程不安全的两个添加是,数据可共享、可修改。Ha...

  • HashMap为什么是线程不安全的

    一直以来只是知道HashMap是线程不安全的,但是到底HashMap为什么线程不安全,多线程并发的时候在什么情况下...

  • HashMap为什么线程不安全

    hash碰撞与扩容导致 一直以来都知道HashMap是线程不安全的,但是到底为什么线程不安全,在多线程操作情况下什...

  • 今日份打卡 237/365

    技术文章SimpleDateFormat是线程不安全的!在多线程环境下测试,看看源码理解一下为什么是不安全的Jav...

  • LocalDateTime

    SimpleDateFormat 线程不安全 SimpleDateFormat format方法是线程不安全的,源...

  • hashmap多线程不安全的原因

    我们知道hashmap在多线程下是不安全的,那么为什么不安全,这个原因是什么呢。其实核心原因在于扩容的时候多线程的...

  • 6-Java并发容器和框架

    1.ConcurrentHashMap ①为什么要使用ConcurrentHashMap 1)线程不安全的Hash...

  • kotlin 单利模式

    1. 懒汉式 java线程不安全 缺点是在多线程不能正常工作 线程安全 效率比较低 kotlin线程不安全 线程...

网友评论

      本文标题:02-SimpleDateFormat为什么线程不安全

      本文链接:https://www.haomeiwen.com/subject/taespktx.html