ThreadLocal示例
本文借花獻(xiàn)佛,引用Tim Cull的博文“SimpleDateFormat: Performance Pig”介紹下ThreadLocal的簡(jiǎn)單使用,同時(shí)也對(duì)SimpleDateFormat的使用有個(gè)深入的了解。
“Great,” you think, “I’ll just create one, static instance, slap it in a field in a DateUtils helper class and life will be good.”
Well, more precisely, life will be good about 97% of the time. A few days after you roll that code into production you’ll discover the second cool fact that’s good to know: SimpleDateFormat is not thread safe. Your code will work just fine most of the time and all of your regression tests will probably pass, but once your system gets under a production load you’ll see the occasional exception.
“Fine,” you think, “I’ll just slap a ’synchronized’ around my use of that one, static instance.”
Ok, fine, you could do that and you’d be more or less ok, but the problem is that you’ve now taken a very common operation (date formatting and parsing) and crammed all of your otherwise-lovely, super-parallel application through a single pipe to get it done.
大致意思:Tim Cull碰到一個(gè)SimpleDateFormat帶來(lái)的嚴(yán)重的性能問(wèn)題,該問(wèn)題主要有SimpleDateFormat引發(fā),創(chuàng)建一個(gè)SimpleDateFormat實(shí)例的開銷比較昂貴,解析字符串時(shí)間時(shí)頻繁創(chuàng)建生命周期短暫的實(shí)例導(dǎo)致性能低下。即使將SimpleDateFormat定義為靜態(tài)類變量,貌似能解決這個(gè)問(wèn)題,但是SimpleDateFormat是非線程安全的,同樣存在問(wèn)題,如果用‘synchronized’線程同步同樣面臨問(wèn)題,同步導(dǎo)致性能下降(線程之間序列化的獲取SimpleDateFormat實(shí)例)。
Tim Cull使用Threadlocal解決了此問(wèn)題,對(duì)于每個(gè)線程SimpleDateFormat不存在影響他們之間協(xié)作的狀態(tài),為每個(gè)線程創(chuàng)建一個(gè)SimpleDateFormat變量的拷貝或者叫做副本,代碼如下:
import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /** * 使用ThreadLocal以空間換時(shí)間解決SimpleDateFormat線程安全問(wèn)題。 * @author * */ 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); } }
創(chuàng)建一個(gè)ThreadLocal類變量,這里創(chuàng)建時(shí)用了一個(gè)匿名類,覆蓋了initialValue方法,主要作用是創(chuàng)建時(shí)初始化實(shí)例。也可以采用下面方式創(chuàng)建;
//第一次調(diào)用get將返回null private static ThreadLocal threadLocal = new ThreadLocal(); //獲取線程的變量副本,如果不覆蓋initialValue,第一次get返回null,故需要初始化一個(gè)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; }
我們看下我們覆蓋的initialValue方法:
protected T initialValue() { return null;//直接返回null }
posted on 2011-05-10 21:01 空白 閱讀(383) 評(píng)論(0) 編輯 收藏 所屬分類: Java