如果你定义了一个单实例的java bean,它有若干属性,但是有一个属性不是线程安全的,比如说HashMap。并且碰巧你并不需要在不同的线程中共享这个属性,也就是说这个属性不存在跨线程的意义。那么你不要sychronize这么复杂的东西,ThreadLocal将是你不错的选择。
举例来说:
package threadlocal; import java.util.TreeMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TreadLocalTest { static ThreadLocal<TreeMap<String, Integer>> map0 = new ThreadLocal<TreeMap<String, Integer>>() { @Override protected TreeMap<String, Integer> initialValue() { System.out.println(Thread.currentThread().getName() + ":initialValue"); return new TreeMap<String, Integer>(); } }; public void run() { ExecutorService es = Executors.newCachedThreadPool(); for (int i = 0; i < 3; i++) { es.execute(new Task(i)); } es.shutdown(); } public static class Task implements Runnable { private int id; public Task(int id) { this.id = id; } public void run() { String threadName = Thread.currentThread().getName(); System.out.println(threadName + ":start"); TreeMap<String, Integer> map = map0.get(); for (int i = 0; i < 5; i++) { map.put(threadName + ":" + i, i + id * 100); try { Thread.sleep(100); } catch (Exception ex) { ex.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + ':' + map); } } public static void main(String[] args) { TreadLocalTest test = new TreadLocalTest(); test.run(); } }
输出解释;
pool-1-thread-1:start pool-1-thread-1:initialValue pool-1-thread-2:start pool-1-thread-2:initialValue pool-1-thread-3:start pool-1-thread-3:initialValue pool-1-thread-1:{pool-1-thread-1:0=0, pool-1-thread-1:1=1, pool-1-thread-1:2=2, pool-1-thread-1:3=3, pool-1-thread-1:4=4} pool-1-thread-2:{pool-1-thread-2:0=100, pool-1-thread-2:1=101, pool-1-thread-2:2=102, pool-1-thread-2:3=103, pool-1-thread-2:4=104} pool-1-thread-3:{pool-1-thread-3:0=200, pool-1-thread-3:1=201, pool-1-thread-3:2=202, pool-1-thread-3:3=203, pool-1-thread-3:4=204}
可以看到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。
http://www.cnblogs.com/alphablox/archive/2013/01/20/2869061.html
package threadlocal; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /*2015-9-15*/ public class KeepObjectStatus { private int times = -1; public int getTimes() { return times; } public static void main(String[] args) { ExecutorService executor = Executors.newCachedThreadPool(); executor.execute(new Task(2)); executor.execute(new Task(5)); executor.shutdown(); } public void process() { if (times < 10) { times++; } } public static ThreadLocal<KeepObjectStatus> instance = new ThreadLocal<KeepObjectStatus>() { @Override protected KeepObjectStatus initialValue() { System.out.println(Thread.currentThread() + " begin to init"); return new KeepObjectStatus(); } }; } class Task implements Runnable { private int step; public Task(int step) { super(); this.step = step; } @Override public void run() { KeepObjectStatus kos = KeepObjectStatus.instance.get(); for (int i = 0; i < 10; i += step) { kos.process(); System.out.println(String.format("%s==> Step:%s %d", Thread.currentThread(), step, kos.getTimes())); } } }
Output:
Thread[pool-1-thread-1,5,main] begin to init Thread[pool-1-thread-2,5,main] begin to init Thread[pool-1-thread-2,5,main]==> Step:5 0 Thread[pool-1-thread-1,5,main]==> Step:2 0 Thread[pool-1-thread-2,5,main]==> Step:5 1 Thread[pool-1-thread-1,5,main]==> Step:2 1 Thread[pool-1-thread-1,5,main]==> Step:2 2 Thread[pool-1-thread-1,5,main]==> Step:2 3 Thread[pool-1-thread-1,5,main]==> Step:2 4