ThreadLocal
ThreadLocal :線程本地變量 也叫 線程本地存儲,ThreadLocal爲變量在每一個線程中創建一個副本,每個線程可以訪問自己內部的副本變量。
這句話理解起來還是比較容易理解的。 建議結合源碼一起看看,比較容易理解哦。
ThreadLocal類中的方法
threadLocal.get(); 獲取ThreadLocal中當前線程共享變量的值
threadLocal.set(); 設置ThreadLocal中當前線程共享變量的值
threadLocal.remove(); 移除ThreadLocal中當前線程共享變量的值
threadLocal.initialValue(); ThreadLocal沒有被當前線程賦值是或者當前線程剛調用remove方法後調用get方法,返回此方法的值。
public class ThreadLocalTest {
.// 創建Threadlocal 對象
ThreadLocal<Long> tl = new ThreadLocal();
ThreadLocal<String> t2 = new ThreadLocal();
public void set( ) {
tl.set(Thread.currentThread().getId());
t2.set(Thread.currentThread().getName());
}
public void getTl() {
System.out.println(tl.get());
System.out.println(t2.get());
}
public static void main(String[] args) {
// main 執行
ThreadLocalTest test = new ThreadLocalTest();
test.set();
test.getTl();
// threads 線程執行
Thread threads = new Thread(){
@Override
public void run() {
test.set();
test.getTl();
}
};
threads.start();
try {
threads.join(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
test.set();
test.getTl();
}
}
執行結果
原理是什麼呢?
Thread.ThreadLocalMap<ThreadLocal, Object>;
Thread:當前線程,可以通過Thread。currentThread()獲取。
ThreadLocal: 是一開始創建的 ThreadLocal對象。
Object :當前線程共享變量
我們調用Threadlocal.get() 方法,實際上就是從當前線程中獲取ThreadLocalMap<ThreadLocal . Object>,然後根據當前ThreadLocal獲取當前線程共享變量Object。
ThreadLocal.set 和 ThreadLocal.remove 也是同樣的原理。
ThreadLocal.get 源碼
/**
* 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();
}
獲得當前線程,通過getMap(t)方法獲取到 ThreadLocalMap 。從map中取值,map爲空就返回setInitialValue();
我們看看 getMap(t)是怎麼實現的。
getMap (Thread) 源碼
/**
* 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;
}
就是返回了一個t.treadLocals; 這個t.threadLocals就是ThreadLocal.ThreadLocalMap 。
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;
}
當前線程的ThreadLocalMap爲空那就創建一個當前線程的ThreadLocalMap他的值爲空。不爲空那就設置當前線程的ThreadLocalmap的值爲空。
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 map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
是不是和setInitialValue()方法非常像。
ThreadLocal.remove 源碼
/**
* Removes the current thread's value for this thread-local
* variable. If this thread-local variable is subsequently
* {@linkplain #get read} by the current thread, its value will be
* reinitialized by invoking its {@link #initialValue} method,
* unless its value is {@linkplain #set set} by the current thread
* in the interim. This may result in multiple invocations of the
* {@code initialValue} method in the current thread.
*
* @since 1.5
*/
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
好了這裏的源碼就展示完了。
貼一下自己寫的代碼:
package com.zw.modules.app.utils;
/**
* Created by lgx on 2019/3/20.
*/
public class ThreadLocalTest2 {
static ThreadLocal<Object> threadLocal = new ThreadLocal<Object>(){
@Override
protected String initialValue() {
return "調用get方法時,如果ThreadLocalMap中沒有值,默認會返回initialValue()方法的返回值。";
}
};
public void set(){
threadLocal.set(Thread.currentThread().getName());
}
public void get(){
System.out.println(threadLocal.get());
}
public void remvoe(){
threadLocal.remove();
}
public static void main(String[] args) {
ThreadLocalTest2 t2 = new ThreadLocalTest2();
t2.set();
t2.get();
for (int i=0; i<5; i++){
if(i==2){
Thread tt = new Thread(){
@Override
public void run() {
t2.remvoe();
t2.get();
}
};
tt.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
Thread tt = new Thread() {
@Override
public void run() {
t2.set();
t2.get();
}
};
tt.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}