SimpleDateFormat 非线程安全

简介: SimpleDateFormat 非线程安全

@[TOC]

前言

类 SimpleDateFormat 主要负责日期的转换与格式化,但在多线程的环境中,使用此类容易造成数据转换及处理的不准确,因为 SimpleDateFormat 类并不是线程安全的。

1.出现异常

  本实例将实现使用类 SimpleDateFormat 类在多线程的环境中处理日期但得出的结果却是错误的情况,这也是再多线程环境开发中容易遇到的问题。
  创建名称为7.4.1项目。
  创建MyThread.java类代码如下:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MyThread extends Thread{
    private SimpleDateFormat sdf;
    private String dateString;

    public MyThread(SimpleDateFormat sdf, String dateString) {
        super();
        this.sdf = sdf;
        this.dateString = dateString;
    }

    @Override
    public void run() {
        try {
            Date dateRef = sdf.parse(dateString);
            String newDateString = sdf.format(dateRef).toString();
            if (!newDateString.equals(dateString)) {
                System.out.println("ThreadName= " + this.getName()
                        + "报错了 日期字符串: " + dateString + " 转换成的日期为: " + newDateString);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

  创建运行类Test.java代码如下:

import java.text.SimpleDateFormat;

public class Test {
    public static void main(String[] args) {
        //共享变量SimpleDateFormat 导致 java.lang.NumberFormatException: multiple points
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String[] dateStringArray = new String[]{"2000-01-01", "2001-02-02", "2003-03-03", "2004-04-04","2004-04-05","2004-04-06","2004-04-07"};
        MyThread[] threadArray = new MyThread[7];
        for (int i = 0; i < dateStringArray.length; i++) {
            threadArray[i] = new MyThread(sdf, dateStringArray[i]);
        }
        for (int i = 0; i < dateStringArray.length; i++) {
            threadArray[i].start();
        }
    }
}

  程序运行后的结果如下所示:

ThreadName= Thread -2 报错了 日期字符串: 2003 -03 -03 转换成的日期为: 2300 -04 -07
ThreadName= Thread -4 报错了 日期字符串: 2004 -04 -05 转换成的日期为: 2300 -04 -07

  从控制台中打印的结果来看,使用单例的 SimpleDateFormat 类在多线程的环境中处理日期,极易出现日期转换错误的情况。

2.解决异常方法 1

  创建名称为7.4.2项目。
  创建MyThread.java类代码如下:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MyThread extends Thread{
    private SimpleDateFormat sdf;
    private String dateString;

    public MyThread(SimpleDateFormat sdf, String dateString) {
        super();
        this.sdf = sdf;
        this.dateString = dateString;
    }

    @Override
    public void run() {
        try {
            Date dateRef = DateTools.parse("yyyy-MM-dd", dateString);
            String newDateString = DateTools.format("yyyy-MM-dd", dateRef);
            if (!newDateString.equals(dateString)) {
                System.out.println("ThreadName= " + this.getName()
                        + "报错了 日期字符串: " + dateString + " 转换成的日期为: " + newDateString);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

  创建类DateTools.java代码如下:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.text.ParseException;

public class DateTools {
    public static Date parse(String formatPattern, String dateString) throws ParseException {
        return new SimpleDateFormat(formatPattern).parse(dateString);
    }
    public static String format(String formatPattern, Date date) {
        return new SimpleDateFormat(formatPattern).format(date).toString();
    }
}

  创建运行类Test.java代码如下:

import java.text.SimpleDateFormat;

public class Test {
    public static void main(String[] args) {
        //共享变量SimpleDateFormat 导致 java.lang.NumberFormatException: multiple points
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String[] dateStringArray = new String[]{"2000-01-01", "2001-02-02", "2003-03-03", "2004-04-04","2004-04-05","2004-04-06","2004-04-07"};
        MyThread[] threadArray = new MyThread[7];
        for (int i = 0; i < dateStringArray.length; i++) {
            threadArray[i] = new MyThread(sdf, dateStringArray[i]);
        }
        for (int i = 0; i < dateStringArray.length; i++) {
            threadArray[i].start();
        }
    }

  程序运行后的结果是控制台输出空白。
  控制台没有输出任何异常,解决处理错误的方法就是创建了多个 SimpleDateFormat 类的实例。

3.解决异常方法 2

  ThreadLocal类能使线程绑定到指定的对象。使用该类也可以解决多线程环境下SimpleDateFormat类处理错误的情况。
  创建名称为7.4.3项目。
  创建MyThread.java类代码如下:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MyThread extends Thread{
    private SimpleDateFormat sdf;
    private String dateString;

    public MyThread(SimpleDateFormat sdf, String dateString) {
        super();
        this.sdf = sdf;
        this.dateString = dateString;
    }

    @Override
    public void run() {
        try {
            Date dateRef = DateTools.getSimpleDateFormat("yyyy-MM-dd").parse(dateString);
            String newDateString = DateTools.getSimpleDateFormat("yyyy-MM-dd").format(dateRef).toString();
            if (!newDateString.equals(dateString)) {
                System.out.println("ThreadName= " + this.getName()
                        + "报错了 日期字符串: " + dateString + " 转换成的日期为: " + newDateString);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

  创建类DateTools.java代码如下:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateTools {
    public static ThreadLocal<SimpleDateFormat> t1 = new ThreadLocal<SimpleDateFormat>();
    public static SimpleDateFormat getSimpleDateFormat(String datePattern) {
        SimpleDateFormat sdf = null;
        sdf = t1.get();
        if (null == sdf) {
            sdf = new SimpleDateFormat(datePattern);
            t1.set(sdf);
        }
        return sdf;
    }
}

  创建运行类Test.java代码如下:

import java.text.SimpleDateFormat;

public class Test {
    public static void main(String[] args) {
        //共享变量SimpleDateFormat 导致 java.lang.NumberFormatException: multiple points
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String[] dateStringArray = new String[]{"2000-01-01", "2001-02-02", "2003-03-03", "2004-04-04","2004-04-05","2004-04-06","2004-04-07"};
        MyThread[] threadArray = new MyThread[7];
        for (int i = 0; i < dateStringArray.length; i++) {
            threadArray[i] = new MyThread(sdf, dateStringArray[i]);
        }
        for (int i = 0; i < dateStringArray.length; i++) {
            threadArray[i].start();
        }
    }
}

  程序运行后的结果是控制台输出空白。
  控制台没有输出任何异常,没有任何信息被输出,看来运行结果是正确的

相关文章
|
3月前
|
安全 Java 开发者
丢失的8小时去哪里了?SimpleDateFormat线程不安全,多线程初始化异常解决方案
丢失的8小时去哪里了?SimpleDateFormat线程不安全,多线程初始化异常解决方案
65 0
|
存储 安全 Java
解密SimpleDateFormat类的线程安全问题和六种解决方案!
提起SimpleDateFormat类,想必做过Java开发的童鞋都不会感到陌生。没错,它就是Java中提供的日期时间的转化类。这里,为什么说SimpleDateFormat类有线程安全问题呢?有些小伙伴可能会提出疑问:我们生产环境上一直在使用SimpleDateFormat类来解析和格式化日期和时间类型的数据,一直都没有问题啊!接下来,我们就一起看下在高并发下SimpleDateFormat类为何会出现安全问题,以及如何解决SimpleDateFormat类的安全问题。
1589 1
解密SimpleDateFormat类的线程安全问题和六种解决方案!
|
安全 Java API
Java Review - SimpleDateFormat线程不安全原因的源码分析及解决办法
Java Review - SimpleDateFormat线程不安全原因的源码分析及解决办法
179 0
|
存储 安全
解决SimpleDateFormat线程安全问题
SimpleDateFormat是线程不安全的类,一般不要定义为static变量,如果定义为static,必须通过加锁等方式保证线程安全。
326 0
|
存储 安全
解决SimpleDateFormat线程安全问题NumberFormatException: multiple points
解决SimpleDateFormat线程安全问题NumberFormatException: multiple points
86 0
SimpleDateFormat 线程安全问题
SimpleDateFormat 线程安全问题
123 0
SimpleDateFormat 线程安全问题
|
安全
浅谈 SimpleDateFormat,第三方库joda-time,JDK8提供时间类 之性能和线程安全
浅谈 SimpleDateFormat,第三方库joda-time,JDK8提供时间类 之性能和线程安全
浅谈 SimpleDateFormat,第三方库joda-time,JDK8提供时间类 之性能和线程安全
|
缓存 安全 Java
java的SimpleDateFormat线程不安全出问题了,虚竹教你多种解决方案
java的SimpleDateFormat线程不安全出问题了,虚竹教你多种解决方案
219 0
java的SimpleDateFormat线程不安全出问题了,虚竹教你多种解决方案
|
缓存 安全 Java
java的SimpleDateFormat线程不安全出问题了,项目不支持java8,虚竹教你这一招
java的SimpleDateFormat线程不安全出问题了,项目不支持java8,虚竹教你这一招
157 0
java的SimpleDateFormat线程不安全出问题了,项目不支持java8,虚竹教你这一招
SimpleDateFormat 为什么不是线程安全的?
大家都说 SimpleDateFormat 不是线程安全的,到底哪里不安全呢? 来看 SimpleDateFormat 类的源码注释:
116 0
SimpleDateFormat 为什么不是线程安全的?