测试代码:

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. docker下安装vim

    进入docker内部后,发现之前的vim命令用不了了,这个时候就需要重新安装vim,具体步骤如下: 更新源 apt-get update 安装vim apt-get install vim

  2. 关于__int64的使用!

    关于__int64的使用! 类型  long long __int64 intmax_t 格式 %lld %I64d %I64d 在Dev C++中,三种类型均需用%I64d格式输出 ,c语言中int ...

  3. 继续畅通工程(hdu1879)并查集

    继续畅通工程 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  4. Mybatis的自动映射autoMappingBehavior与mapUnderscoreToCamelCase

    autoMappingBehavior 在Mybatis的配置文件中添加settings属性的autoMappingBehavior <settings> <setting name ...

  5. mysql小试题

    1. 用户登录日志表 xes_user_login_logs 如下: (1) 检索登录超过两次的用户ID(sql语句) select user_id from vvt_ceshi group by u ...

  6. Code Signal_练习题_variableName

    Correct variable names consist only of English letters, digits and underscores and they can't start ...

  7. JavaScript高级编程——引用类型、Array数组使用、栈方法

    JavaScript高级编程——引用类型.Array数组使用.栈方法 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999 ...

  8. ThinkPHP5事务回滚

    使用事务处理的话,需要数据库引擎支持事务处理.比如 MySQL 的 MyISAM 不支持事务处理,需要使用 InnoDB 引擎. 使用 transaction 方法操作数据库事务,当发生异常会自动回滚 ...

  9. 页面中多个script块之间方法与变量共享问题

    JS是按照代码块来进行编译和执行的,代码块间相互独立,但变量和方法共享,按顺序执行. 如: <script type='text/javascript'> var m = 0,n = 1, ...

  10. DOM基础练习代码(二)

    上一篇给大家的三段代码不知到大家有没有练习呢?今天再给大家带来两段DOM的练习! 4.封装函数,实现children功能,最好哎原型链上编程 Element.prototype.getChildren ...