它是java中的一個為每個執行緒單獨保存資料的類,也就是執行緒間資料隔離,
1.使用
public static void main(String[] args) throws Exception {
//定義一個ThreadLocal
ThreadLocal<String> local = new ThreadLocal<String>();
new Thread(new Runnable() {
@Override
public void run() {
//為當前執行緒設定一個值
local.set("thread1");
try {
//執行緒休眠為了等一下其它執行緒設定值
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//列印
System.out.println("第1個執行緒值"+local.get());
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
local.set("thread2");
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("第2個執行緒值"+local.get());
}
}).start();
}
結果:

說明每個執行緒取到了自己的資料,
2.原理
先看一看ThreadLocal的set方法:
/**
* 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物件
ThreadLocalMap map = getMap(t);
if (map != null)
//設定值
map.set(this, value);
else
//創建ThreadLocalMap物件
createMap(t, value);
}
先看一下getMap(t);我們發現getMap(t);取得是當前執行緒的threadLocals屬性也就是說變數實際是存在每個執行緒自己的屬性中的,
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
然后我們看一下ThreadLocalMap是什么類,
他是一個ThreadLocal中的內部類類似Map,他里面也有一個重要的內部類` static class Entry extends WeakReference<ThreadLocal<?>>
注意它是一個弱參考,
關于java中參考型別以后有時間再寫,
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
//將鍵設定為弱參考
super(k);
value = v;
}
}
接下來看一下創建ThreadLocalMap物件 createMap(t, value);
void createMap(Thread t, T firstValue) {
//這個this是當前ThreadLocal物件
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
//重點是這里將當前ThreadLocal物件設定為弱參考了
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
其實就是創建一個ThreadLocalMap將key,value存進去,
最后get方法就相對簡單了
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();
}
就是從當前執行緒取出ThreadLocalMap再根據當前ThreadLocal物件取出值,
3.記憶體泄漏問題
ThreadLocalMap的key是當前ThreadLocal為一個弱參考,當我們不想使用ThreadLocal時將它設定為null了,也就是要被垃圾回收器回收了,但是此時我們的ThreadLocalMap生命周期和Thread的一樣,它不會回收,這時候就出現了一個現象,那就是ThreadLocalMap的key沒了,但是value還在,這就造成了記憶體泄漏,
所以最好在不使用ThreadLocal時,呼叫一下remove()方法移除存盤的值,
這是我總結的我對ThreadLocal的理解,有不對的地方大家可以討論,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/263436.html
標籤:java
下一篇:多執行緒的創建
