如果你定义了一个单实例的java bean,它有若干属性,但是有一个属性不是线程安全的,比如说HashMap。并且碰巧你并不需要在不同的线程中共享这个属性,也就是说这个属性不存在跨线程的意义。那么你不要sychronize这么复杂的东西,ThreadLocal将是你不错的选择。
package Thread; import java.util.HashMap; /** * Created by dingpeng on 2016/1/20. */ public class ThreadLocalTest { static ThreadLocal<HashMap> map0 = 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 = map0.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){ ThreadLocalTest test = new ThreadLocalTest(); test.run(); } }
可以看到map0 虽然是个静态变量,但是initialValue被调用了三次,通过debug发现,initialValue是从map0.get处发起的。而且每个线程都有自己的map,虽然他们同时执行。
进入Theadlocal代码,可以发现如下的片段;
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(); }
这说明ThreadLocal确实只有一个变量,但是它内部包含一个map,针对每个thread保留一个entry,如果对应的thread不存在则会调用initialValue。