java中常常使用ThreadLocal做爲處理高併發訪問的可選手段,ThreadLocal並非一個線程,而是」以線程爲做用域「的一種面向對象的數據結構。其用法的也有着讓人難以理解的怪異性。java
定義一個線程類,其中定義了一個ThreadLocal<Integer> 的對象數據結構
class AutoIntegerThread extends Thread { //靜態局部變量(注意java中的靜態變量的生命週期,共享性,惟一性) private static ThreadLocal<Integer> autoInteger = new ThreadLocal<Integer>(); //自增次數 private int runTimes; public AutoIntegerThread(int runTimes) { this.runTimes = runTimes; } @Override public void run() { //爲了說明ThreadLocal以線程爲做用域,這裏不適用同步代碼塊 if(autoInteger.get()==null) { autoInteger.set(new Integer(0)); } for (int i = 0; i < runTimes; i++) { autoInteger.set(autoInteger.get()+1); //這裏使用如下,保證完整打印一下 synchronized (autoInteger) { System.out.println(getName()+"==>"+autoInteger.get().intValue()); } } } public Integer getFinalInteger() { return autoInteger.get(); } }
測試代碼併發
public class TestThreadLocal { public static void main(String[] args) { AutoIntegerThread ait_1 = new AutoIntegerThread(5); AutoIntegerThread ait_2 = new AutoIntegerThread(3); AutoIntegerThread ait_3 = new AutoIntegerThread(3); ait_1.setName("ait_1"); ait_2.setName("ait_3"); ait_3.setName("ait_2"); ait_1.start(); ait_2.start(); ait_3.start(); } }
打印結果ide
ait_1==>1 ait_2==>1 ait_2==>2 ait_2==>3 ait_1==>2 ait_3==>1 ait_1==>3 ait_3==>2 ait_1==>4 ait_3==>3 ait_1==>5
有上面的代碼和代碼註釋可知,符合java中的靜態變量的描述,【靜態變量的生命週期和應用程序的生命週期徹底相同。靜態變量具備共享性,惟一性,也就是說是單例】高併發
是的,靜態變量能夠說是一個完整的單例,但由打印結果可知,彷佛狀況卻違反了這種邏輯。測試
首先仔細想一想,單例的好處是下降了內存的使用,從而提升程序的執行效率(這裏不可過度理解,其實,當靜態變量太多時反而也會影響內存的回收,由於他的生命週期決定了他和程序時「同壽的」,靜態變量儘可能少用的好,萬事講究一個「度」),另外單例的惟一性說明了他很是適合作「同步鎖」。this
其次,從結果來看,貌似誰也沒影響誰。有人質疑是否是 private 的問題,建議java基礎不熟練的話就不要問這樣的問題了,由於private只決定訪問權限,而不決定變量的建立。所以也就說明了,以線程爲做用域。spa
if(autoInteger.get()==null) { autoInteger.set(new Integer(0)); }
從這段代碼來看,若是是List集合來講,只會運行一次,但程序彷佛並無這麼作,而是分別在每一個線程個執行了一次。線程
看看源代碼code
java.lang.ThreadLocal<T>
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } 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(); }
很顯然,這個域做爲map的key而存在,也就是說以「線程域」來建立和讀取數據
而這個map的是屬於Thread,看下面的源碼
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
然而,進一步證實了threadlocal使用線程域
java.lang.Thread
ThreadLocal.ThreadLocalMap threadLocals = null;
static class ThreadLocalMap {....}
反正是個map,版面估計不足,不粘了,你們能夠去看看。
總結:ThreadLocal經過「線程域」能夠實現做用域的區分,並使得程序更加高效