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

}

  这种结果没有异常。

原文地址:https://www.cnblogs.com/windy13/p/11336384.html

时间: 2024-09-30 07:04:09

《java多线程编程核心技术》----simpleDateFormat非线程安全的相关文章

SimpleDateFormat非线程安全

以前没有注意过的问题呀! 留着 自己好好看看. 出自 :http://www.cnblogs.com/zemliu/p/3290585.html 1. 原因 SimpleDateFormat(下面简称sdf)类内部有一个Calendar对象引用,它用来储存和这个sdf相关的日期信息,例如sdf.parse(dateStr), sdf.format(date) 诸如此类的方法参数传入的日期相关String, Date等等, 都是交友Calendar引用来储存的.这样就会导致一个问题,如果你的sdf

SimpleDateFormat非线程安全及解决办法

一. 为什么SimpleDateFormat不是线程安全的? Java源码如下: /** * Date formats are not synchronized. * It is recommended to create separate format instances for each thread. * If multiple threads access a format concurrently, it must be synchronized * externally. */ pu

关于 SimpleDateFormat 的非线程安全问题及其解决方案

1.问题: 先来看一段可能引起错误的代码: package test.date; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; public class ProveNotSafe { static SimpleDateFormat df = new SimpleDateFormat("dd-MMM-yyyy&qu

python之多线程执行和非线程执行的对比

一.非线程执行(普通的执行) 1.非线程运行,简单代码如下 #_*_coding:utf-8_*_ import time import threading a = [] b = [] def func1():     print "func1 start %s" % time.ctime()     alist = ["192.168.1.100","192.168.1.120","192.168.1.134","

2016/07/07 PHP的线程安全与非线程安全版本的区别

Windows版的PHP从版本5.2.1开始有Thread Safe(线程安全)和None Thread Safe(NTS,非线程安全)之分,这两者不同在于何处?到底应该用哪种?这里做一个简单的介绍. 从2000年 10月20日发布的第一个Windows版的PHP3.0.17开始的都是线程安全的版本,这是由于与Linux/Unix系统是采用多进程的工作方式不 同的是Windows系统是采用多线程的工作方式.如果在IIS下以CGI方式运行PHP会非常慢,这是由于CGI模式是建立在多进程的基础之上的

所谓线程安全和非线程安全

ArrayList和Vector有什么区别?HashMap和HashTable有什么区别?StringBuilder和StringBuffer有什么区别?这些都是Java面试中常见的基础问题.面对这样的问题,回答是:ArrayList是非线程安全的,Vector是线程安全的:HashMap是非线程安全的,HashTable是线程安全的:StringBuilder是非线程安全的,StringBuffer是线程安全的.这些是面试时经常问道的问题,但是有些情况下面试的人会追问:什么是线程安全,什么是非

PHP版本的线程安全与非线程安全

Thread Safe与None-Thread Safe等的区别: 线程安全就是在多线程环境下也不会出现数据不一致,而非线程安全就有可能出现数据不一致的情况. 线程安全由于要确保数据的一致性,所以对资源的读写进行了控制,换句话说增加了系统开销.所以在单线程环境中效率比非线程安全的效率要低些,但是如果线程间数据相关,需要保证读写顺序,用线程安全模式 这个主要是针对web server 而言,在windows环境下,如果你使用的web server 是apchae 或者 iis 7以下版本,则应该选

Windows下的PHP开发环境搭建——PHP线程安全与非线程安全、Apache版本选择,及详解五种运行模式。

今天为在Windows下建立PHP开发环境,在考虑下载何种PHP版本时,遭遇一些让我困惑的情况,为了解决这些困惑,不出意料地牵扯出更多让我困惑的问题. 为了将这些困惑一网打尽,我花了一下午加一晚上的时间查阅了大量资料,并做了一番实验后,终于把这些困惑全都搞得清清楚楚了. 说实话,之所以花了这么多时间,很大程度上是由于网上的资料几乎全都是支离破碎.以讹传讹的.既然我已经搞懂了,就花时间整理出来,即方便自己看,也便于大家阅读.相信通过这篇文章,可以解答很多在Windows下搭建PHP开发环境的朋友的

JAVA中的线程安全与非线程安全

原文:http://blog.csdn.net/xiao__gui/article/details/8934832 ArrayList和Vector有什么区别?HashMap和HashTable有什么区别?StringBuilder和StringBuffer有什么区别?这些都是Java面试中常见的基础问题.面对这样的问题,回答是:ArrayList是非线程安全的,Vector是线程安全的:HashMap是非线程安全的,HashTable是线程安全的:StringBuilder是非线程安全的,St