拾遗增补(四)——SimpleDateFormat 非线程安全

文章通过示例展示了在多线程环境下使用SimpleDateFormat进行日期转换时可能出现的异常,以及两种解决方案:创建多个实例和使用ThreadLocal保证每个线程拥有独立的SimpleDateFormat对象,从而避免数据转换错误。
摘要由CSDN通过智能技术生成

  类 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();
        }
    }
}

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


以上代码下载请点击该链接:https://github.com/Yarrow052/Java-package.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值