《java多线程编程核心技术》----simpleDateFormat非线程安全

Posted windy13

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《java多线程编程核心技术》----simpleDateFormat非线程安全相关的知识,希望对你有一定的参考价值。

类simpleDateFormat主要负责日期的转换和格式化,但在多线程的环境中,使用此内容容易造成数据转换以及处理的不准确,

因为simpleDateFormat类并不是线程安全的。

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 
            // dateString 传入的日期字符串
            Date dateRef = sdf.parse(dateString);
            // newDateString 根据传入的字符串转换成日期,然后,在转换后的字符串
            String newDateString= sdf.format(dateRef).toString();
            if(!newDateString.equals(dateString))
                System.out.println("ThreadName="+this.getName()
                +"报错了 日期字符串:"+dateString+" 转换成的日期为:"+newDateString);
            
         catch (ParseException e) 
            e.printStackTrace();
        
    

测试,以及结果

public class Test 

    public static void main(String[] args) 
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        String[] dateStringArray=new String[]
                "2001-01-01","2000-01-02","2000-01-03",
                "2001-01-04","2000-01-05","2000-01-06",
                "2001-01-07","2000-01-08","2000-01-09","2000-01-10"
        ;

        MyThread[] threadArray=new MyThread[10];
        for (int i = 0; i < 10; i++) 
            threadArray[i]=new MyThread(sdf,dateStringArray[i]);
        
        for (int i = 0; i < 10; i++) 
            threadArray[i].start();
        
    


ThreadName=Thread-1报错了 日期字符串:2000-01-02 转换成的日期为:1970-01-01
ThreadName=Thread-4报错了 日期字符串:2000-01-05 转换成的日期为:1970-01-01
ThreadName=Thread-3报错了 日期字符串:2001-01-04 转换成的日期为:1970-01-01
ThreadName=Thread-2报错了 日期字符串:2000-01-03 转换成的日期为:2000-01-01

 

使用单例的simpleDateFormat类在多线程的环境中处理,容易出错。

 

解决方法一

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();
    
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 
            // dateString 传入的日期字符串
            Date dateRef = DateTools.parse("yyyy-MM-dd",dateString);
            // newDateString 根据传入的字符串转换成日期,然后,在转换后的字符串
            String newDateString= DateTools.format("yyyy-MM-dd",dateRef);
            if(!newDateString.equals(dateString))
                System.out.println("ThreadName="+this.getName()
                +"报错了 日期字符串:"+dateString+" 转换成的日期为:"+newDateString);
            else
                System.out.println("ThreadName="+this.getName()
                        +" 日期字符串:"+dateString+" 转换成的日期为:"+newDateString);
            
         catch (ParseException e) 
            e.printStackTrace();
        
    

 

没有任何异常,解决处理错误的原理其实就是创建多个simpleDateFormat类的实例;

 

解决方法二

threadlocal类能使线程绑定到指定的对象。

public class DateTools 

    // ThreadLocal相当于一个map,key为线程的标识,value为每个线程设置的value
    private static ThreadLocal<SimpleDateFormat> t1 = new ThreadLocal<>();

    public static SimpleDateFormat getSimpleDateFormat(String datePattern) 
        SimpleDateFormat sdf = null;
        sdf = t1.get();
        if (sdf == null) 
            sdf = new SimpleDateFormat(datePattern);
            t1.set(sdf);
        
        return sdf;
    
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 
            // dateString 传入的日期字符串
            Date dateRef = DateTools.getSimpleDateFormat("yyyy-MM-dd").parse(dateString);
            // newDateString 根据传入的字符串转换成日期,然后,在转换后的字符串
            String newDateString= DateTools.getSimpleDateFormat("yyyy-MM-dd").format(dateRef).toString();
            if(!newDateString.equals(dateString))
                System.out.println("ThreadName="+this.getName()
                +"报错了 日期字符串:"+dateString+" 转换成的日期为:"+newDateString);
            else
                System.out.println("ThreadName="+this.getName()
                        +" 日期字符串:"+dateString+" 转换成的日期为:"+newDateString);
            
         catch (ParseException e) 
            e.printStackTrace();
        
    


  这种结果没有异常。

 

以上是关于《java多线程编程核心技术》----simpleDateFormat非线程安全的主要内容,如果未能解决你的问题,请参考以下文章

java多线程编程核心技术

《Java多线程编程核心技术》推荐

《Java多线程编程核心技术》多线程技能

java多线程编程核心技术学习-2

《java多线程编程核心技术》

java多线程编程核心技术----心得1