测试代码:

public class Main {

    public static void main(String[] args) {

        for (int k = 0; k < 10; k++) {

            Runnable target = new Runnable() {

                @Override
public void run() {
Object obj = dateFormatter.get();
System.out.println(Thread.currentThread().getName() + " => " + obj);
obj = dateFormatter.get();
}
};
new Thread(target, k+"").start(); } } private static final ThreadLocal<SimpleDateFormat> dateFormatter = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
}
};
}

输出结果:

8 => java.text.SimpleDateFormat@f67a0200
5 => java.text.SimpleDateFormat@f67a0200
6 => java.text.SimpleDateFormat@f67a0200
...
7 => java.text.SimpleDateFormat@f67a0200

咦?怎么全是f67a0200一个实例?跟踪ThreadLocal代码寻找原因,百思不得其解。最后突然怀疑是SimpleDateFormat中toString方法的问题,SimpleDateFormat#toString源码如下:

    public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

SimpleDateFormat#hashCode代码如下,其中pattern变量是SimpleDateFormat的格式字符串值( public SimpleDateFormat(String pattern))。

    @Override
public int hashCode()
{
return pattern.hashCode();
// just enough fields for a reasonable distribution
}

 

所以如上原因可以得知,由于自己实现的initialValue方法的SimpleDateFormat的pattern都一样,所以不同sdf实例的toString最终输出相同。

     protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
}

  

产生困惑原因:

  通常子类在没有重写toString方法时,我们都可以简单的根据toString值进行判断是否是一个实例,但是由于SimpleDateFormat自己实现了toString所以这个规则不在生效。

提醒:

  以后尽可能不要简单的将toString输出用来判断是否是一个实例,如果需要这么判断的话一定要检查toString方法。

拓展:

  在java.lang.ThreadLocal#getMap方法中可以发现原来java的Thread对线程局部变量自身就有支持,在Thread中有一个ThreadLocalMap的成员变量。java.lang.ThreadLocal#getMap源码如下:

    ThreadLocalMap getMap(Thread t) {
     //threadLocals是一个默认修饰符成员变量
return t.threadLocals;
}

  

ThreadLocal解决SimpleDateFormat多线程安全问题中遇到的困惑的更多相关文章

  1. 【Java并发编程】12、ThreadLocal 解决SimpleDateFormat非线程安全

    大致意思:Tim Cull碰到一个SimpleDateFormat带来的严重的性能问题,该问题主要有SimpleDateFormat引发,创建一个 SimpleDateFormat实例的开销比较昂贵, ...

  2. 解决SimpleDateFormat线程安全问题

    package com.tanlu.user.util; import java.text.DateFormat; import java.text.ParseException; import ja ...

  3. ThreadLocal 解决simpledateformat线程不安全

    SimpleDateFormat在多线程情况下会出现线程不安全的情况,故用ThreadLoacl 处理/** * 用ThreadLocal处理simplDateFormat线程不安全 */public ...

  4. ThreadLocal解决线程安全问题

    一.线程安全问题产生的原因 线程安全问题都是由全局变量及静态变量引起的 二.线程安全问题 SimpleDateFormate sdf = new SimpleDateFormat();使用sdf.pa ...

  5. NET中解决KafKa多线程发送多主题

    NET中解决KafKa多线程发送多主题 一般在KafKa消费程序中消费可以设置多个主题,那在同一程序中需要向KafKa发送不同主题的消息,如异常需要发到异常主题,正常的发送到正常的主题,这时候就需要实 ...

  6. Spring单例模式多线程安全问题-有状态的Bean

    Spring单例与线程安全小结 一.Spring单例模式与线程安全 Spring框架里的bean,或者说组件,获取实例的时候都是默认的单例模式,这是在多线程开发的时候要尤其注意的地方. 单例模式的意思 ...

  7. ThreadLocal解决了什么问题

    小明所在的项目组(迭代组:一直在迭代的路上),经常会在已有接口的基础上开发一些小功能,并且前提是在保证现有用户的不受影响基础上迭代.功能迭代,在代码层面小明有1w种实现方法(吹牛的),一起来看看这次小 ...

  8. ThreadLocal解决什么问题

    原创文章,转载请务必将下面这段话置于文章开头处(保留超链接).本文转发自技术世界,原文链接 http://www.jasongj.com/java/threadlocal/ ThreadLocal解决 ...

  9. SimpleDateFormat线程安全问题排查

    一. 问题现象 运营部门反馈使用小程序配置的拉新现金红包活动二维码,在扫码后跳转至404页面. 二. 原因排查 首先,检查扫码后的跳转链接地址不是对应二维码的实际URL,根据代码逻辑推测,可能是acc ...

随机推荐

  1. curl 使用示例 详细

    NAMEcurl - transfer a URL SYNOPSIScurl [options] [URL...] DESCRIPTIONcurl is a client to get documen ...

  2. Arrays工具类的aslist()方法的使用

    数组转换成集合: 数组转换成集合不能增加或减少元素,但是可以用集合思想操作数组,也就是说可以使用其他集合中的办法 String[] arr = {"a", "b" ...

  3. 了解java虚拟机—堆相关参数设置(3)

    堆相关配置 -Xmx 最大堆空间 -Xms 初始堆空间大小,如果初始堆空间耗尽,JVM会对堆空间扩容,其扩展上限为最大堆空间.通常-Xms与-Xmx设置为同样大小,避免扩容造成性能损耗. -Xmn 设 ...

  4. Random类的常用方法

    1.nextBoolean(): 随机返回true或false 2.nextInt(int bound): 随机返回0到bound之间的整数(不包括bound) 如:nextInt(10)返回0-9之 ...

  5. Windows平台如何部署scrapy

    0.安装Anaconda 这个不教了,自己去Anaconda官网上下个安装包,装上就好. https://www.anaconda.com/distribution/ 1.使用Anaconda创建一个 ...

  6. POJ3281(KB11-B 最大流)

    Dining Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 19170   Accepted: 8554 Descripti ...

  7. js-ES6学习笔记-Promise对象

    1.Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大. 2.所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作) ...

  8. Mybatis中使用循环遍历

    Mybatis中传参数的方法 1.使用注解绑定,mapper.xml 对应方法 不需要指定 parameterType,(推荐使用注解绑定方式) 方法接口: List<CalculateIdea ...

  9. SpringBoot简介、特点

    ##SpringBoot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包.SpringBoot整合了所有的框架,并通过一行简单的main方法启动应用. ##微框 ...

  10. Oracle常用方法备份

    1.UNION ALL 和UNION.INTERSECT.MINUS 连接所有的查询结果.去掉重复的结果.操作返回查询结果中公共的行.在进行两个表格或者两个查询结果的时候,返回在第一个表格/查询结果中 ...