重要方法的源码分析
ThreadLocal主要方法源碼解析?
?
- public T get() :get方法是先取出當前線程的ThreadLocalMap,然后調用map.getEntry方法,把本ThreadLocal的引用作為參數傳入,取出map中屬于本ThreadLocal的value
- 注意這個map以及map中的key和value都是保存在線程中的,而不是保存在ThreadLocal中
public void set(T value) :和setInitialValue()方法很類似
public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value); }void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue); }initialValue()
protected T initialValue() {return null; }??該方法返回當前線程局部變量的初始化值。當第一次使用get方法訪問變量時調用該方法,但若該線程在這之前調用了set方法,則不會調用initialValue方法。正常情況下,該方法最多被調用一次,但是如果后續調 用了remove,然后再調用get,則該方法可能再次被調用。
withInitial()
public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {return new SuppliedThreadLocal<>(supplier); }??用于創建一個線程局部變量,變量的初始化值通過調用Supplier的get方法來確定,例子如下:
import java.util.function.Supplier;
輸出為:8
public void remove()方法
public void remove() {ThreadLocalMap m = getMap(Thread.currentThread());if (m != null)m.remove(this); }private void remove(ThreadLocal<?> key) {Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCode & (len-1);for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {if (e.get() == key) {e.clear();expungeStaleEntry(i);return;}} }?
?該方法用于清除當前線程局部變量的值。變量值被清除后,若當前線程隨后通過get讀取該變量的值,則initialValue方法會再次被調用對變量進行初始化,除非在此期間調用了set方法。
??經過上面的分析,可知通過ThreadLocal創建的變量是維護在線程內部的,這就意味著線程只要不退出,那么對象的引用將一直存在。當線程退出的時候會進行一些清理工作,如下所示:
private void exit() {if (group != null) {group.threadTerminated(this);group = null;}/* Aggressively null out all reference fields: see bug 4006245 */target = null;//加速資源清理,threadLocals為ThreadLocal.ThreadLocalMap類型threadLocals = null;inheritableThreadLocals = null;inheritedAccessControlContext = null;blocker = null;uncaughtExceptionHandler = null; }此方法為private型,通過系統調用,給線程一個機會在其實際退出之前清理資源。
??上面多次出現了ThreadLocalMap類,有必要說明一下。ThreadLocalMap的實現采用了弱引用,弱引用在垃圾回收的時候被發現就會被回收。ThreadLocalMap內部由一系列的Entry構成,每一個Entry都是WeakReference<ThreadLocal>類型的:
內部維護一個Entry數組,用于存放線程的變量
private Entry[] table;例子:
public class ThreadLocalDemo implements Runnable{ private static ThreadLocal<Integer> tl=new ThreadLocal<Integer>(); @Override public void run() {// TODO Auto-generated method stubif(tl.get()==null)tl.set(new Integer(1));System.out.print(tl.get()+"\t");}public static void main(String args[]) {int k=0;for(int i=0;i<1000;i++) {Thread t=new Thread(new ThreadLocalDemo());t.start();}} }輸出全為1,即每一個線程都維護自己的一個變量副本
?
總結
- 上一篇: ThreadLocal的重要方法介绍
- 下一篇: 两种场景,殊途同归