版权声明:本文为博主总结文章,未经博主允许您依然可以转载。 https://blog.csdn.net/Memery_last/article/details/60876726
使用ThreadLocal可以用来和线程绑定特定的变量,不能被其它的线程使用。来看一个例子:
public class DateUtils {
public static final String DATE_FMT = "yyyy-MM-dd";
public static final String DATE_FMT1 = "yyyy-MM-dd HH:mm:ss";
private static Map<String, ThreadLocal<SimpleDateFormat>> formatMap = Maps.newConcurrentMap();
public static Date toDate(String date) {
return toDate(date, DATE_FMT);
}
public static Date toDate(String date, String fmt) {
if (StringUtils.isBlank(date)) {
return null;
}
try {
final SimpleDateFormat sdf = getFormat(fmt);
return sdf.parse(date);
} catch (Exception ex) {
return null;
}
}
public static String format(Date date) {
return format(date, DATE_FMT);
}
public static String format(Date date, String fmt) {
if (date == null) {
return null;
}
try {
final SimpleDateFormat sdf = getFormat(fmt);
return sdf.format(date);
} catch (Exception ex) {
return null;
}
}
public static SimpleDateFormat getFmt(String fmt) {
return getFormat(fmt);
}
private static SimpleDateFormat getFormat(final String fmt) {
ThreadLocal<SimpleDateFormat> fmtLocal = formatMap.get(fmt);
if (fmtLocal == null) {
synchronized (DateUtils.class) {
fmtLocal = formatMap.get(fmt);
if (fmtLocal == null) { // Double-Check
fmtLocal = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat(fmt);
};
};
formatMap.put(fmt, fmtLocal);
}
}
}
return fmtLocal.get();
}
}
关注其中的getFormat方法
1)SimpleDateFormat不是线程安全的;
2)定义Map key是dateFormat,value是ThreadLocal对象;
3)使用Double-check的方法为每个线程创建SimpleDateFormat单例;
4)内部类重写ThreadLocal initialValue方法,返回new SimpleDateFormat;
5)调用ThreadLocal get方法获取SimpleDateFormat,具体看ThreadLocal中get方法的实现,及其调用关系;
public class ThreadLocal<T> {
/**
* Returns the current thread's "initial value" for this
* thread-local variable. This method will be invoked the first
* time a thread accesses the variable with the {@link #get}
* method, unless the thread previously invoked the {@link #set}
* method, in which case the <tt>initialValue</tt> method will not
* be invoked for the thread. Normally, this method is invoked at
* most once per thread, but it may be invoked again in case of
* subsequent invocations of {@link #remove} followed by {@link #get}.
*
* <p>This implementation simply returns <tt>null</tt>; if the
* programmer desires thread-local variables to have an initial
* value other than <tt>null</tt>, <tt>ThreadLocal</tt> must be
* subclassed, and this method overridden. Typically, an
* anonymous inner class will be used.
*
* @return the initial value for this thread-local
*/
protected T initialValue() {
return null;
}
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
/**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
/**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
*
* @return the initial value
*/
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
/**
* Create the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @param firstValue value for the initial entry of the map
* @param map the map to store.
*/
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
}
6)threadLocals为 Thread类中的属性,由ThreadLocal类来维护。
public
class Thread implements Runnable {
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
}