zoukankan      html  css  js  c++  java
  • 【Java并发编程】12、ThreadLocal 解决SimpleDateFormat非线程安全

    大致意思:Tim Cull碰到一个SimpleDateFormat带来的严重的性能问题,该问题主要有SimpleDateFormat引发,创建一个 SimpleDateFormat实例的开销比较昂贵,解析字符串时间时频繁创建生命周期短暂的实例导致性能低下。即使将 SimpleDateFormat定义为静态类变量,貌似能解决这个问题,但是SimpleDateFormat是非线程安全的,同样存在问题,如果用 ‘synchronized’线程同步同样面临问题,同步导致性能下降(线程之间序列化的获取SimpleDateFormat实例)。

    早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。

    ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程”。其实,ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些。

    当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

    从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。

    Tim Cull使用Threadlocal解决了此问题,对于每个线程SimpleDateFormat不存在影响他们之间协作的状态,为每个线程创建一个SimpleDateFormat变量的拷贝或者叫做副本,代码如下:

    import java.text.DateFormat;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    /** 
     * 使用ThreadLocal以空间换时间解决SimpleDateFormat线程安全问题。 
     */
    public class DateUtil {
        private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
        @SuppressWarnings("rawtypes")
        private static ThreadLocal threadLocal = new ThreadLocal() {
            protected synchronized Object initialValue() {
                return new SimpleDateFormat(DATE_FORMAT);
            }
        };
    
        public static DateFormat getDateFormat() {
            return (DateFormat) threadLocal.get();
        }
    
        public static Date parse(String textDate) throws ParseException {
            return getDateFormat().parse(textDate);
        }
    }

    创建一个ThreadLocal类变量,这里创建时用了一个匿名类,覆盖了initialValue方法,主要作用是创建时初始化实例。也可以采用下面方式创建;

    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    
    /** 
     * 使用ThreadLocal以空间换时间解决SimpleDateFormat线程安全问题
     */
    public class DateUtil {    
        private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
        private static ThreadLocal threadLocal = new ThreadLocal();
        // 第一次调用get将返回null
        // 获取线程的变量副本,如果不覆盖initialValue,第一次get返回null,
        // 故需要初始化一个SimpleDateFormat,并set到threadLocal中
        public static DateFormat getDateFormat() {
            DateFormat df = (DateFormat) threadLocal.get();
            if (df == null) {
                df = new SimpleDateFormat(DATE_FORMAT);  
                threadLocal.set(df);
            }
            return df;
        }
    }

    当然也可以使用:

    apache commons-lang包的DateFormatUtils或者FastDateFormat实现,apache保证是线程安全的,并且更高效

  • 相关阅读:
    装饰器
    提供离线chrome谷歌浏览器插件crx的网站有
    关于使用AWS上的RHEL8.x/Redhat系统使用自己单独购买的Redhat官网license导致的yum命令报错处理
    关于aws账单数据中几个重要的与费用相关的字段的意义分析
    在vCenter或者ESXi中通过ova/ovf进行还原部署虚拟机的过程记录
    关于python爬虫request.get()方法的常用参数
    关于aws cli命令的exit/return code分析
    关于pycharm代码运行后控制台的输出不完整被截断的处理
    关于变量的值中包含另一个变量引用的处理间接变量引用
    关于在python中使用pandas模块将列表list/元组tuple写入excel中
  • 原文地址:https://www.cnblogs.com/wangzhongqiu/p/6597636.html
Copyright © 2011-2022 走看看