ThreadLocal怎么在Java項目中使用?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
讓客戶滿意是我們工作的目標,不斷超越客戶的期望值來自于我們對這個行業的熱愛。我們立志把好的技術通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領域值得信任、有價值的長期合作伙伴,公司提供的服務項目有:主機域名、虛擬主機、營銷軟件、網站建設、開原網站維護、網站推廣。
ThreadLocal是在多線程環境下經常使用的一個類。
ThreadLocal適用的場景是,多個線程都需要使用一個變量,但這個變量的值不需要在各個線程間共享,各個線程都只使用自己的這個變量的值。這樣的場景下,可以使用ThreadLocal。此外,我們使用ThreadLocal還能解決一個參數過多的問題。例如一個線程內的某個方法f1有10個參數,而f1調用f2時,f2又有10個參數,這么多的參數傳遞十分繁瑣。那么,我們可以使用ThreadLocal來減少參數的傳遞,用ThreadLocal定義全局變量,各個線程需要參數時,去全局變量去取就可以了。
接下來我們看一下ThreadLocal的源碼。首先是類的介紹。如下圖。這個類提供了線程本地變量。這些變量使每個線程都有自己的一份拷貝。ThreadLocal期望能夠管理一個線程的狀態,例如用戶id或事務id。例如下面的例子產生線程本地的唯一id。線程的id是第一次調用時進行復制,并且在后面的調用中保持不變。
This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable. ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID). For example, the class below generates unique identifiers local to each thread. A thread's id is assigned the first time it invokes ThreadId.get() and remains unchanged on subsequent calls. import java.util.concurrent.atomic.AtomicInteger; public class ThreadId { // Atomic integer containing the next thread ID to be assigned private static final AtomicInteger nextId = new AtomicInteger(0); // Thread local variable containing each thread's ID private static final ThreadLocal<Integer> threadId = new ThreadLocal<Integer>() { @Override protected Integer initialValue() { return nextId.getAndIncrement(); } }; // Returns the current thread's unique ID, assigning it if necessary public static int get() { return threadId.get(); } } Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive and the ThreadLocal instance is accessible; after a thread goes away, all of its copies of thread-local instances are subject to garbage collection (unless other references to these copies exist).
下面看一下set方法。
set方法的作用是,把線程本地變量的當前線程的拷貝設置為指定的值。大部分子類無需重寫該方法。首先獲取當前線程,然后獲取當前線程的ThreadLocalMap。如果ThreadLocalMap不為null,則設置當前線程的值為指定的值,否則調用createMap方法。
獲取線程的ThreadLocalMap對象,是直接返回的線程的threadLocals,類型為ThreadLocalMap。也就是說,每個線程都有一個ThreadLocalMap對象,用于保存該線程關聯的所有的ThreadLocal類型的變量。ThreadLocalMap的key是ThreadLocal,value是該ThreadLocal對應的值。具體什么意思呢?在程序中,我們可以定義不止一個ThreadLocal對象,一般會有多個,比如定義3個ThreadLocal<String>,再定義2個ThreadLocal<Integer>,而每個線程可能都需要訪問全部這些ThreadLocal的變量,那么,我們用什么數據結構來實現呢?當然,最好的方式就是像源碼中的這樣,每個線程有一個ThreadLocalMap,key為ThreadLocal變量名,而value為該線程在該ThreadLocal變量的值。這個設計實在是太巧妙了。
寫到這里,自己回想起之前換工作面試時,面試官問自己關于ThreadLocal的實現原理。那個時候,為了準備面試,自己只在網上看了一些面試題,并沒有真正掌握,在回答這個問題時,我有印象,自己回答的是用一個map,線程的id值作為key,變量值作為value,誒,露餡了啊。
/** * Sets the current thread's copy of this thread-local variable * to the specified value. Most subclasses will have no need to * override this method, relying solely on the {@link #initialValue} * method to set the values of thread-locals. * @param value the value to be stored in the current thread's copy of * this thread-local. **/ public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } /** * Get the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * @param t the current thread * @return the map **/ ThreadLocalMap getMap(Thread t) { return t.threadLocals; } /** * Create the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * @param t the current thread * @param firstValue value for the initial entry of the map **/ void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
接下來看一下get方法。
源碼如下。首先獲取當前線程的ThreadLocalMap,然后,從ThreadLocalMap獲取該ThreadLocal變量對應的value,然后返回value。如果ThreadLocalMap為null,則說明該線程還沒有設置該ThreadLocal變量的值,那么就返回setInitialValue方法的返回值。其中的initialValue方法的返回值,通常情況下為null。但是,子類可以重寫initialValue方法以返回期望的值。
/** * Returns the value in the current thread's copy of this * thread-local variable. If the variable has no value for the * current thread, it is first initialized to the value returned * by an invocation of the {@link #initialValue} method. * @return the current thread's value of this thread-local **/ 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(); } /** * Variant of set() to establish initialValue. Used instead * of set() in case user has overridden the set() method. * @return the initial value **/ private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; } protected T initialValue() { return null; }
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注創新互聯行業資訊頻道,感謝您對創新互聯的支持。
文章名稱:ThreadLocal怎么在Java項目中使用
新聞來源:http://vcdvsql.cn/article28/poogjp.html
成都網站建設公司_創新互聯,為您提供移動網站建設、ChatGPT、App設計、用戶體驗、品牌網站制作、網站制作
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯