SimpleDateFormat线程不安全原因及解决方案

线程不安全验证:

/**
 * SimpleDateFormat线程安全测试
 * 〈功能详细描述〉
 *
 * @author 17090889
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class SimpleDateFormatTest {
    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000), new MyThreadFactory("SimpleDateFormatTest"));

    public void test() {
        while (true) {
            poolExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    String dateString = simpleDateFormat.format(new Date());
                    try {
                        Date parseDate = simpleDateFormat.parse(dateString);
                        String dateString2 = simpleDateFormat.format(parseDate);
                        System.out.println(dateString.equals(dateString2));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

输出:

true
false
true
true
false

出现了false,说明线程不安全

1、format方法

public StringBuffer format(Date date, StringBuffer toAppendTo,
                               FieldPosition pos)
    {
        pos.beginIndex = pos.endIndex = 0;
        return format(date, toAppendTo, pos.getFieldDelegate());
    }

    // Called from Format after creating a FieldDelegate
    private StringBuffer format(Date date, StringBuffer toAppendTo,
                                FieldDelegate delegate) {
        // Convert input date to time field list
        calendar.setTime(date);

        boolean useDateFormatSymbols = useDateFormatSymbols();

        for (int i = 0; i < compiledPattern.length; ) {
            int tag = compiledPattern[i] >>> 8;
            int count = compiledPattern[i++] & 0xff;
            if (count == 255) {
                count = compiledPattern[i++] << 16;
                count |= compiledPattern[i++];
            }

            switch (tag) {
            case TAG_QUOTE_ASCII_CHAR:
                toAppendTo.append((char)count);
                break;

            case TAG_QUOTE_CHARS:
                toAppendTo.append(compiledPattern, i, count);
                i += count;
                break;

            default:
                subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
                break;
            }
        }
        return toAppendTo;
    }
 protected Calendar calendar;

可以看到,多个线程之间共享变量calendar,并修改calendar,因此在多线程环境下,线程是不安全的。

解决方案:

1、将SimpleDateFormat定义成局部变量

2、 加一把线程同步锁:synchronized(lock)

3、使用ThreadLocal,每个线程都拥有自己的SimpleDateFormat对象副本

  如:

/**
 * SimpleDateFormat线程安全测试
 * 〈功能详细描述〉
 *
 * @author 17090889
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class SimpleDateFormatTest {
    ThreadLocal<SimpleDateFormat> local = new ThreadLocal<>();
    //    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000), new MyThreadFactory("SimpleDateFormatTest"));

    public void test() {
        while (true) {
            poolExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    SimpleDateFormat simpleDateFormat = local.get();
                    if (simpleDateFormat == null) {
                        simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    }
                    String dateString = simpleDateFormat.format(new Date());
                    try {
                        Date parseDate = simpleDateFormat.parse(dateString);
                        String dateString2 = simpleDateFormat.format(parseDate);
                        System.out.println(dateString.equals(dateString2));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

4、使用DateTimeFormatter代替SimpleDateFormat

原文地址:https://www.cnblogs.com/yangyongjie/p/11017409.html

时间: 2024-10-31 03:39:41

SimpleDateFormat线程不安全原因及解决方案的相关文章

并发条件下SimpleDateFormat线程不安全及解决方案

1.使用线程池创建并发环境解析日期 package com.zh.time; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util

Activity中获取view的高度和宽度为0的原因以及解决方案

在activity中可以调用View.getWidth.View.getHeight().View.getMeasuredWidth() .View.getgetMeasuredHeight()来获得某个view的宽度或高度,但是在onCreate().onStrart().onResume()方法中会返回0,这是应为当前activity所代表的界面还没显示出来没有添加到WindowPhone的DecorView上或要获取的view没有被添加到DecorView上或者该View的visibili

iOS构建流畅的交互界面--CPU,GPU资源消耗的原因和解决方案

 CPU资源消耗的原因和解决方案对象创建轻量对象代替重量对象* 不需要响应触摸事件的控件:CALayer显示* 对象不涉及UI操作,则尽量放到后台线程创建* 包含有CALayer的控件只能在主线程创建和操作* 通过Storyboard 创建视图对象时,其资源消耗会比直接通过代码创建对象要大非常多,在性能敏感的界面里,storyboard不是一个好的技术选择* 尽量推迟对象创建的时间,并把对象的创建分散到多个任务中去.* 对象的复用代价比释放,创建新对象要小,这类对象应当尽量放到一个缓存池里复用对

XP下切换输入法造成程序卡死的原因及解决方案

http://blog.csdn.net/ysai/article/details/7468961 XP下切换输入法造成程序卡死的原因及解决方案 (by ysai) 现象: 在XP下,如果线程中创建了窗口而线程中没有消息循环,那么可能切换输入法时会造成程序卡死(某些XP下必现,跟安装盘有关) 原因: 线程创建一个窗口后,系统会自动创建一个Default IME窗口以便通知输入法消息(可能只有可以接收输入的窗口才会创建,未证实) XP下切换输入法,会向所有DefaultIME窗口SendMessa

Java并发编程原理与实战八:产生线程安全性问题原因(javap字节码分析)

前面我们说到多线程带来的风险,其中一个很重要的就是安全性,因为其重要性因此,放到本章来进行讲解,那么线程安全性问题产生的原因,我们这节将从底层字节码来进行分析. 一.问题引出 先看一段代码 package com.roocon.thread.t3; public class Sequence { private int value; public int getNext(){ return value++; } public static void main(String[] args) { S

PC电脑运行Android模拟器总是弹出“视频源”窗体的原因和解决方案

原因: PC电脑运行Android模拟器时弹出“视频源”窗体,会让你"选择视频设备",如:HP TruevIsion HD,而这个视频设备就是你电脑中的内置摄像头,这个内置摄像头在你的电脑的:计算机管理-->设备管理器-->图像管理下可以找到:正是由于启动模拟器的时候检测到了该内置摄像头,所以会弹窗提示选择. 解决办法: 第一步:通过右键"我的电脑"选中"管理"-->计算机管理-->设备管理器-->图像管理 或者通过

String内存溢出异常(错误)可能的原因及解决方案

摘要:本Blog主要为了阐述java.lang.OutOfMemoryError:PermGenspace可能产生的原因及解决方案.其中PermGen space是Permanent Generationspace的简写,表示内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGenspace中,它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen

&quot;Insufficient RAM for Flash Algorithms&quot;出错原因及解决方案

"Insufficient RAM for Flash Algorithms"错误一般会有一个"cannot load flash programming algorithm !"的提示窗口,如下图: "Insufficient RAM for Flash Algorithms"从字面上解释是:"装载FLASH算法的RAM空间不足". 这个错误一般出现在添加了新的FLASH烧写算法以后. 原因:FLASH的烧写算法本身也相当于

信用评分卡模型开发中双峰分布原因及解决方案

信用评分卡模型开发中双峰分布原因及解决方案 文: 郑旻圻 邹钰 刘巧莉 转自:  数信互融 在信用评分卡模型开发过程中,正态性是检验模型信用评分分布是否有效的一个重要指标.正常情况下,标准的正态分布是单峰分布:但是在实际建模过程中,会遇到信用评分分布出现双峰的情况. 双峰分布出现时,数据规律一致性的假设被打破,我们需要从不同的角度考察其出现双峰分布的原因,对模型加以调整,使之准确地反映业务和数据中的规律,以便模型准确适用. 根据为数十家互联网金融企业建立评分卡模型的实践经验,我们总结了一些造成双