背景:
如果你定义了一个单实例的java bean,它有若干属性,但是有一个属性不是线程安全的,比如说HashMap。
并且碰巧你并不需要在不同的线程中共享这个属性,也就是说这个属性不存在跨线程的意义。
那么你不要sychronize这么复杂的东西,ThreadLocal将是你不错的选择。
why:
因为线程同步限制了并发访问,会带来很大的性能损失。
误解:
ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程”。
正解:
其实 ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易理解。
从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。
举例来说:
package com.xzc.util; import java.util.HashMap; /** * @Descrption * @Author xingzc * @Date 2018/11/9 10:18 */ public class TreadLocalTest { static ThreadLocal<HashMap> mapThreadLocal = new ThreadLocal<HashMap>() { @Override protected HashMap initialValue() { System.out.println(Thread.currentThread().getName() + "initialValue"); return new HashMap(); } }; public void run() { Thread[] runs = new Thread[3]; for (int i = 0; i < runs.length; i++) { runs[i] = new Thread(new T1(i)); } for (int i = 0; i < runs.length; i++) { runs[i].start(); } } public static class T1 implements Runnable { int id; public T1(int id0) { id = id0; } public void run() { System.out.println(Thread.currentThread().getName() + ":start"); HashMap map = mapThreadLocal.get(); for (int i = 0; i < 10; i++) { map.put(i, i + id * 100); try { Thread.sleep(100); } catch (Exception ex) { } } System.out.println(Thread.currentThread().getName() + ':' + map); } } /** * Main * * @param args */ public static void main(String[] args) { TreadLocalTest test = new TreadLocalTest(); test.run(); } }
输出解释;
Thread-0:start Thread-2:start Thread-1:start Thread-2initialValue Thread-0initialValue Thread-1initialValue Thread-0:{0=0, 1=1, 2=2, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8, 9=9} Thread-2:{0=200, 1=201, 2=202, 3=203, 4=204, 5=205, 6=206, 7=207, 8=208, 9=209} Thread-1:{0=100, 1=101, 2=102, 3=103, 4=104, 5=105, 6=106, 7=107, 8=108, 9=109}
结论:
1) mapThreadLocal虽然是个静态变量,但是initialValue被调用了三次,通过debug发现,initialValue是从mapThreadLocal.get处发起的;
2) ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本 ,变量是线程安全的共享对象;
3) ThreadLocal确实只有一个变量,但是它内部包含一个ThreadLocalMap,针对每个thread保留一个entry,如果对应的thread不存在则会调用initialValue;
源码解析:
Theadlocal 代码片段;
/** * 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) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } 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; }
在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。
参考