Java ThreadLocal的用法解析

簡介

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經過「線程域」能夠實現做用域的區分,並使得程序更加高效

相關文章
相關標籤/搜索