运用ThreadLocal模式的场景:
1.频繁创建生命周期短暂的实例(或者实例化代价昂贵)导致性能低下
2.需要线程安全,使用‘synchronized’线程同步同样导致性能低下
以下是Tim Cull的博文“SimpleDateFormat: Performance Pig”解决满足这一需求采用ThreadLocal模式的案列
Tim Cull 写道:
Tim Cull碰到一个SimpleDateFormat带来的严重的性能问题,该问题主要有SimpleDateFormat引发,创建一个 SimpleDateFormat实例的开销比较昂贵,解析字符串时间时频繁创建生命周期短暂的实例导致性能低下。即使将 SimpleDateFormat定义为静态类变量,貌似能解决这个问题,但是SimpleDateFormat是非线程安全的,同样存在问题,如果用 ‘synchronized’线程同步同样面临问题,同步导致性能下降(线程之间序列化的获取SimpleDateFormat实例)。
Tim Cull使用Threadlocal解决了此问题,对于每个线程SimpleDateFormat不存在影响他们之间协作的状态,为每个线程创建一个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); } }
public class Counter { public static Integer number =10; }
public class LocalCounter { public Integer number =10; private static ThreadLocal<LocalCounter> counter = new ThreadLocal<LocalCounter>(){ protected synchronized LocalCounter initialValue(){ return new LocalCounter(); } };//初始需要覆盖初始化方法,不覆盖第一次调用get方法值为null,使用前需要先调set方法初始化 public static LocalCounter getCounter() { return (LocalCounter) counter.get(); } public static void setCounter(LocalCounter counterFrom){ counter.set(counterFrom); } }
public class ThreadLocalStub extends Thread { public void run() { for (int i = 0; i < 2; i++) { LocalCounter localCounter = LocalCounter.getCounter();//当前使用时不用再次创建 System.out.println("Thread[" + Thread.currentThread().getName() + "],localCounter=" + localCounter.number++); System.out.println("Thread[" + Thread.currentThread().getName() + "],Counter=" + Counter.number++); LocalCounter.setCounter(localCounter); } nextAdd(); } private void nextAdd(){ LocalCounter localCounter = LocalCounter.getCounter();//当前使用时不用再次创建,线程上共享 System.out.println("Thread[" + Thread.currentThread().getName() + "],localCounter=" + localCounter.number++); System.out.println("Thread[" + Thread.currentThread().getName() + "],Counter=" + Counter.number++); LocalCounter.setCounter(localCounter); } }
public class ThreadLocalTest { public static void main(String[] args) { ThreadLocalStub testThread1 = new ThreadLocalStub(); ThreadLocalStub testThread2 = new ThreadLocalStub(); ThreadLocalStub testThread3 = new ThreadLocalStub(); testThread1.start(); testThread2.start(); testThread3.start(); } }运行结果: