此次想總結ThreadLocal這個東西,也是因爲項目中使用到了它去幫助保存會話信息。傳統的(或者說我在學校的時候)方法,大可能是用服務端的session保存會話,與瀏覽器端的cookie協做去追蹤這個會話。而如今更多的使用ThreadLocal去保存會話的信息,這是因爲ThreadLocal天生帶有線程安全的特性,而且僅僅在一個線程內共享變量(剛好符合多用戶多會話請求這一場景),這就使得這種方式用起來十分順手和簡單。瀏覽器
1. 項目中的使用:安全
首先記錄一下項目中ThreadLocal是如何保存用戶會話信息的:cookie
1 private final String KEY_USER = "user"; 2 private final String KEY_TICKET = "ticket"; 3 private final String KEY_ROLEKEY = "roleKey"; 4 5 private static class Inner{ 6 static LocalThreadUtils localThreadUtils = new LocalThreadUtils(); 7 } 8 9 public static LocalThreadUtils getInstance(){ 10 return Inner.localThreadUtils; 11 } 12 13 14 private ThreadLocal<Map<String, Object>> threadLocal = ThreadLocal.withInitial(() -> Maps.newHashMap()); 15 16 17 public void cleanContext(){ 18 threadLocal.get().clear(); 19 }
核心就是這樣一個內部類的單例模式,產生的單例有一個theadLocal私有變量,用ThreadLocal修飾,內部是一個Map,而這個map能夠由咱們本身去存放用戶的各類信息,好比ticket,角色role,用戶信息user等。session
ThreadLocal這種方式的優勢在於實現簡單,並不須要咱們在每一層傳遞request,也不用考慮httpSession的做用域,咱們能夠再任意層(controller,service等)直接訪問當前線程信息,從而取出會話信息。spa
2. 實現方式和原理:線程
ThreadLocal類是如何爲每一個線程建立一個變量的副本的:code
首先,在每一個線程Thread內部有一個ThreadLocal.ThreadLocalMap類型的成員變量threadLocals,這個threadLocals就是用來存儲實際的變量副本的,鍵值爲當前ThreadLocal變量,value爲變量副本(即T類型的變量)。對象
初始時,在Thread裏面,threadLocals爲空,當經過ThreadLocal變量調用get()方法或者set()方法,就會對Thread類中的threadLocals進行初始化,而且以當前ThreadLocal變量爲鍵值,以ThreadLocal要保存的副本變量爲value,存到threadLocals。blog
而後在當前線程裏面,若是要使用副本變量,就能夠經過get方法在threadLocals裏面查找。生命週期
其餘想要說的:
ThreadLocal真的不是用來解決對象共享訪問問題的,而主要是提供了保持對象的方法和避免參數傳遞的方便的對象訪問方式。
一、每一個線程中都有一個本身的ThreadLocalMap類對象,能夠將線程本身的對象保持到其中,各管各的,線程能夠正確的訪問到本身的對象。
二、將一個共用的ThreadLocal靜態實例做爲key,將不一樣對象的引用保存到不一樣線程的ThreadLocalMap中,而後在線程生命週期內執行的各處經過這個靜態ThreadLocal實例的get()方法取得本身線程保存的那個對象,避免了將這個對象做爲參數傳遞的麻煩。
寫在最後:這裏只是對ThreadLocal作一個小小的總結,由於在以前的項目中歷來沒有真正使用過,只是字面上瞭解他的含義。不少知識確實要經過實踐纔能有更深入的理解。