SimpleDateFormat的线程安全性

SimpleDateFormat 是线程不安全类,在定义为static时可能出现线程安全问题;推荐使用DateUtils工具类。下面的示例将给出错误的和正确的代码。

首先是错误的代码,执行Demo会发现,在某些竞态条件下报错。

 

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

/**
 * Created by Administrator on 2016/10/25.
 */
public class MyThread extends Thread {
    private String dateString;
    private SimpleDateFormat simpleDateFormat;

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

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


package wrong;

import java.text.SimpleDateFormat;

public class Demo {
    static SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd");
    public static void main(String[] args) {
        String[] dateStringArray = new String[]{
                "2000-01-01", "2001-01-01", "2002-01-01", "2003-01-01", "2004-01-01",
                "2005-01-01", "2006-01-01", "2007-01-01", "2008-01-01", "2009-01-01"
        };
        MyThread[] myThreads = new MyThread[10];
        for (int i = 0; i < 10; i++) {
            myThreads[i] = new MyThread(dateStringArray[i],simpleDateFormat);
        }
        for (int i = 0; i < 10; i++)
            myThreads[i].start();
    }
}

 

 

下面是正确的代码,利用了ThreadLocal的特性,保证每个线程有且只有一个专用的SimpleDateFormat.

 

package correct;

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

public class MyThread extends Thread {
    private String dateString;
    public MyThread( String dateString) {
        super();
        this.dateString = dateString;
    }
    @Override
    public void run() {
        Date dateRef = null;
        try {
            dateRef = DateUtils.getSimpleDateFormat("yyyy-MM-dd").parse(dateString);
            String newDateString = DateUtils.getSimpleDateFormat("yyyy-MM-dd").format(dateRef).toString();
            if (!newDateString.equals(dateString))
                System.out.println("thread" + this.getName() + "报错了 字符串=" + dateString + " 转换成" + newDateString);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

package correct;

import java.text.SimpleDateFormat;

/**
 * Created by Administrator on 2016/10/25.
 */
public class DateUtils {
    private static ThreadLocal<SimpleDateFormat> simpleDateFormatThreadLocal=new ThreadLocal<SimpleDateFormat>();

    public static SimpleDateFormat getSimpleDateFormat(String pattern){
        if(simpleDateFormatThreadLocal.get()==null)
            simpleDateFormatThreadLocal.set(new SimpleDateFormat(pattern));
        return simpleDateFormatThreadLocal.get();
    }
}

package correct;

public class Demo {
    public static void main(String[] args) {
        String[] dateStringArray = new String[]{
                "2000-01-01", "2001-01-01", "2002-01-01", "2003-01-01", "2004-01-01",
                "2005-01-01", "2006-01-01", "2007-01-01", "2008-01-01", "2009-01-01"
        };
        MyThread[] myThreads = new MyThread[10];
        for (int i = 0; i < 10; i++) {
            myThreads[i] = new MyThread(dateStringArray[i]);
        }
        for (int i = 0; i < 10; i++)
            myThreads[i].start();
    }
}

 

 

 

SimpleDateFormat的线程安全性是编码时一个常见的坑,要注意正确使用。

提供给想深入学习和提高JAVA并发编程能力的同学,欢迎收听https://www.zhihu.com/lives/1018219399903387648

提供给想学习云计算的同学,欢迎收听https://www.zhihu.com/lives/1046567982750281728

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值