搜公众号
推荐 原创 视频 Java开发 开发工具 Python开发 Kotlin开发 Ruby开发 .NET开发 服务器运维 开放平台 架构师 大数据 云计算 人工智能 开发语言 其它开发 iOS开发 前端开发 JavaScript开发 Android开发 PHP开发 数据库
Lambda在线 > SimpleDateFormat非线程安全

SimpleDateFormat非线程安全

2018-05-14
举报

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

出现异常

本示例将实现实用类SimpleDateFormat在多线程环境下处理日期但得出的结果却是错误的情况,这也是在多线程环境开发中容易遇到的问题。

类MyThread.java代码如下:

 
   
   
 
  1. import java.text.ParseException;

  2. import java.text.SimpleDateFormat;

  3. import java.util.Date;

  4. public class MyThread extends Thread {

  5.    private SimpleDateFormat sdf;

  6.    private String dateString;

  7.    public MyThread(SimpleDateFormat sdf, String dateString) {

  8.        super();

  9.        this.sdf = sdf;

  10.        this.dateString = dateString;

  11.    }

  12.    @Override

  13.    public void run() {

  14.        try {

  15.            Date dateRef = sdf.parse(dateString);

  16.            String newDateString = sdf.format(dateRef).toString();

  17.            if (!newDateString.equals(dateString)) {

  18.                System.out.println("ThreadName=" + this.getName()

  19.                        + "报错了 日期字符串:" + dateString + " 转换成的日期为:"

  20.                        + newDateString);

  21.            }

  22.        } catch (ParseException e) {

  23.            e.printStackTrace();

  24.        }

  25.    }

  26. }

运行类Test.java代码如下:

 
   
   
 
  1. import java.text.SimpleDateFormat;

  2. import extthread.MyThread;

  3. public class Test {

  4.    public static void main(String[] args) {

  5.        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

  6.        String[] dateStringArray = new String[] { "2000-01-01", "2000-01-02",

  7.                "2000-01-03", "2000-01-04", "2000-01-05", "2000-01-06",

  8.                "2000-01-07", "2000-01-08", "2000-01-09", "2000-01-10" };

  9.        MyThread[] threadArray = new MyThread[10];

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

  11.            threadArray[i] = new MyThread(sdf, dateStringArray[i]);

  12.        }

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

  14.            threadArray[i].start();

  15.        }

  16.    }

  17. }

程序运行后的结果如下:

 
   
   
 
  1. ThreadName=Thread-4报错了 日期字符串:2000-01-05 转换成的日期为:2000-02-24

  2. ThreadName=Thread-5报错了 日期字符串:2000-01-06 转换成的日期为:0005-02-24

  3. ThreadName=Thread-8报错了 日期字符串:2000-01-09 转换成的日期为:0001-01-10

  4. ThreadName=Thread-9报错了 日期字符串:2000-01-10 转换成的日期为:0001-01-10

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

解决异常方法1

类MyThread.java代码如下:

 
   
   
 
  1. import java.text.ParseException;

  2. import java.text.SimpleDateFormat;

  3. import java.util.Date;

  4. import tools.DateTools;

  5. public class MyThread extends Thread {

  6.    private SimpleDateFormat sdf;

  7.    private String dateString;

  8.    public MyThread(SimpleDateFormat sdf, String dateString) {

  9.        super();

  10.        this.sdf = sdf;

  11.        this.dateString = dateString;

  12.    }

  13.    @Override

  14.    public void run() {

  15.        try {

  16.            Date dateRef = DateTools.parse("yyyy-MM-dd", dateString);

  17.            String newDateString = DateTools.format("yyyy-MM-dd", dateRef)

  18.                    .toString();

  19.            if (!newDateString.equals(dateString)) {

  20.                System.out.println("ThreadName=" + this.getName()

  21.                        + "报错了 日期字符串:" + dateString + " 转换成的日期为:"

  22.                        + newDateString);

  23.            }

  24.        } catch (ParseException e) {

  25.            e.printStackTrace();

  26.        }

  27.    }

  28. }

类DateTools.java代码如下:

 
   
   
 
  1. public class DateTools {

  2.    public static Date parse(String formatPattern, String dateString)

  3.            throws ParseException {

  4.        return new SimpleDateFormat(formatPattern).parse(dateString);

  5.    }

  6.    public static String format(String formatPattern, Date date) {

  7.        return new SimpleDateFormat(formatPattern).format(date).toString();

  8.    }

  9. }

运行类Test.java代码与前面一节是一样的。 控制台中没有输入任何异常。解决处理错误的原理其实就是创建了多个SimpleDateFormat类的实例。

解决异常方法2

ThreadLocal类能使线程绑定到指定的对象。使用该类也可以解决多线程环境下SimpleDateFormat类处理错误的情况。

类MyThread.java代码如下:

 
   
   
 
  1. import java.text.ParseException;

  2. import java.text.SimpleDateFormat;

  3. import java.util.Date;

  4. import tools.DateTools;

  5. public class MyThread extends Thread {

  6.    private SimpleDateFormat sdf;

  7.    private String dateString;

  8.    public MyThread(SimpleDateFormat sdf, String dateString) {

  9.        super();

  10.        this.sdf = sdf;

  11.        this.dateString = dateString;

  12.    }

  13.    @Override

  14.    public void run() {

  15.        try {

  16.            Date dateRef = DateTools.getSimpleDateFormat("yyyy-MM-dd").parse(dateString);

  17.            String newDateString = DateTools.getSimpleDateFormat("yyyy-MM-dd")

  18.                    .format(dateRef).toString();

  19.            if (!newDateString.equals(dateString)) {

  20.                System.out.println("ThreadName=" + this.getName()

  21.                        + "报错了 日期字符串:" + dateString + " 转换成的日期为:"

  22.                        + newDateString);

  23.            }

  24.        } catch (ParseException e) {

  25.            e.printStackTrace();

  26.        }

  27.    }

  28. }

类DateTools.java代码如下:

 
   
   
 
  1. import java.text.SimpleDateFormat;

  2. public class DateTools {

  3.    private static ThreadLocal<SimpleDateFormat> tl = new ThreadLocal<SimpleDateFormat>();

  4.    public static SimpleDateFormat getSimpleDateFormat(String datePattern) {

  5.        SimpleDateFormat sdf = null;

  6.        sdf = tl.get();

  7.        if (sdf == null) {

  8.            sdf = new SimpleDateFormat(datePattern);

  9.            tl.set(sdf);

  10.        }

  11.        return sdf;

  12.    }

  13. }

运行类Test.java代码与前面小节是一样的。 控制台没有信息被输出,看来运行结果是正确的。


版权声明:本站内容全部来自于腾讯微信公众号,属第三方自助推荐收录。《SimpleDateFormat非线程安全》的版权归原作者「Zong在路上」所有,文章言论观点不代表Lambda在线的观点, Lambda在线不承担任何法律责任。如需删除可联系QQ:516101458

文章来源: 阅读原文

相关阅读

举报