ThreadLocal的解析

來源:互聯網
上載者:User


一  概述
 
ThreadLocal是什麼。ThreadLocal並非是一個線程的本地實現版本,它並不是一個Thread,而是線程局部變數—threadlocalvariable。也許把它命名為ThreadLocalVar更加合適。ThreadLocal其實的功用非常簡單,就是為每一個使用該變數的線程都提供一個變數值的副本,是Java中一種較為特殊的線程綁定機制,是每一個線程都可以獨立地改變自己的副本,而不會和其它線程的副本衝突。
 
從線程的角度看,每個線程都保持一個對其線程局部變數副本的隱式引用,只要線程是活動的並且ThreadLocal執行個體是可訪問的;線上程消失之後,其線程局部執行個體的所有副本都會被記憶體回收(除非存在對這些副本的其他引用)。
 
通過ThreadLocal存取的資料,總是與當前線程相關,JVM為每個啟動並執行線程,綁定了私人的本地執行個體存取空間,從而為多線程環境常出現的並發訪問問題提供了一種隔離機制。
 
ThreadLocal是如何做到為每一個線程維護變數的副本的呢。思路很簡單,在ThreadLocal類中有一個Map,用於儲存每一個線程的變數的副本。
 
對於多線程資源共用的問題,


同步機制採用了以時間換空間的方式,僅提供一份變數,讓不同的線程排隊訪問。
ThreadLocal採用了以空間換時間的方式,每一個線程都提供了一份變數,因此可以同時訪問而互不影響。





二  API說明
 
ThreadLocal()
建立一個執行緒區域變數。


T get() 
返回此線程局部變數的當前線程副本中的值,如果這是線程第一次調用該方法,則建立並初始化此副本。 


protected T initialValue() 
返回此線程局部變數的當前線程的初始值。最多在每次訪問線程來獲得每個線程局部變數時調用此方法一次,即線程第一次使用get()方法訪問變數的時候。如果線程先於get方法調用set(T)方法,則不會線上程中再調用initialValue方法。若該實現只返回null;如果程式員希望將線程局部變數初始化為null以外的某個值,則必須為ThreadLocal建立子類,並重寫此方法。通常,將使用匿名內部類。initialValue的典型實現將調用一個適當的構造方法,並返回新構造的對象。


void remove() 
移除此線程局部變數的值。這可能有助於減少線程局部變數的儲存需求。如果再次訪問此線程局部變數,那麼在預設情況下它將擁有其 initialValue。 


void set(T value) 
將此線程局部變數的當前線程副本中的值設定為指定值。許多應用程式不需要這項功能,它們只依賴於initialValue()方法來設定線程局部變數的值。在程式中一般都重寫initialValue方法,以給定一個特定的初始值。


public class ThreadLocal
{
 private Map values = Collections.synchronizedMap(new HashMap());
 public Object get()
 {
  Thread curThread = Thread.currentThread(); 
  Object o = values.get(curThread); 
  if (o == null && !values.containsKey(curThread))
  {
   o = initialValue();
   values.put(curThread, o); 
  }
  return o; 
 }


 public void set(Object newValue)
 {
  values.put(Thread.currentThread(), newValue);
 }


 public Object initialValue()
 {
  return null; 
 }
} 



三 典型執行個體
 
Hiberante的Session工具類HibernateUtil。這個類是Hibernate官方文檔中HibernateUtil類,用於session管理。
 
public class HibernateUtil 
{
    private static Log log = LogFactory.getLog(HibernateUtil.class);
    private static final SessionFactory sessionFactory;
 
    static 
    {
        try 
        {
            // 通過預設設定檔hibernate.cfg.xml建立SessionFactory
            sessionFactory = new Configuration().configure().buildSessionFactory();
        } 
        catch (Throwable ex) 
        {
            log.error("初始化SessionFactory失敗。", ex);
            throw new ExceptionInInitializerError(ex);
        }
    }


    // 建立線程局部變數session用來儲存Hibernate的Session
    public static final ThreadLocal session = new ThreadLocal();
 
    // 擷取當前線程中的Session
    public static Session currentSession() throws HibernateException 
    {
        Session s = (Session) session.get();
        if (s == null) 
        {
            // 將新開的Session儲存到線程局部變數中
            s = sessionFactory.openSession();
            session.set(s);
        }
        return s;
    }
 
    public static void closeSession() throws HibernateException 
    {
        Session s = (Session) session.get();
        session.set(null);
        if (s != null)
            s.close();
    }
}




對代碼進行分析


1  public static final ThreadLocal session = new ThreadLocal(); 
2  public static Session currentSession() { 
3      Session s = (Session)session.get(); 
4      if(s == null){ 
5          s = sessionFactory.openSession(); 
6          session.set(s); 
7      } 
8      return s; 
9  } 


總體分析

該類由於沒有重寫ThreadLocal的initialValue()方法,則首次建立線程局部變數session其初始值為null。第一次調用currentSession()的時候,線程局部變數的get()方法也為null。因此對session做了判斷如果為null,則新開一個Session,並儲存到線程局部變數session中,這一步非常的關鍵。


逐行分析

第一行 
初始化。如果不初始化initialvalue則initialvalue為null。 

第三行
session的get根據當前線程返回其對應的線程內部變數,也就是我們需要的net.sf.hibernate.Session相當於對應每個資料庫連接。多線程情況下共用資料庫連結是不安全的。ThreadLocal保證了每個線程都有自己的s資料庫連接。 

第四行
如果是該線程初次訪問,自然s會是null,接著建立一個Session,具體就是第五行。 

第五行
建立一個資料庫連接執行個體s。

第六行
儲存該資料庫連接s到ThreadLocal中。 

第七行
如果當前線程已經訪問過資料庫了,則從session中get()就可以擷取該線程上次擷取過的串連執行個體。 



四 總結
 

ThreadLocal使用場合主要解決多線程中資料因並發產生不一致問題。ThreadLocal為每個線程的中並發訪問的資料提供一個副本。

 

原帖地址:http://lavasoft.blog.51cto.com/62575/51926/


 


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.