ThreadLocal是為了使每個線程保存一份屬于自己的數據。
先看一個使用ThreadLocal的實例。
package org.springframework.aop.framework;
import org.springframework.core.NamedThreadLocal;
public abstract class AopContext {
private static final ThreadLocal<Object> currentProxy = new NamedThreadLocal<Object>("Current AOP proxy");
public static Object currentProxy() throws IllegalStateException {
Object proxy = currentProxy.get();
if (proxy == null) {
throw new IllegalStateException(
"Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.");
}
return proxy;
}
static Object setCurrentProxy(Object proxy) {
Object old = currentProxy.get();
if (proxy != null) {
currentProxy.set(proxy);
}
else {
currentProxy.remove();
}
return old;
}
}
上例展示的是spring框架中獲取當前線程的代理對象的方法,AopContext.currentProxy(),在本線程的程序調用棧中只要調用AopContext的靜態方法就可以獲取本線程相關的代理對象。如果不用ThreadLocal,那么這個代理對象在創建后,就要一層層傳遞下去,才能在后面獲取到并使用。
通過這個例子,我們可以知道[b]ThreadLocal主要是提供了一種保持對象的方法以及避免了對象在程序調用中傳遞的簡便訪問方法。ThreadLocal與共享數據和同步沒有明顯關系。[/b]
下面看看相關的源碼以了解具體的結構。
public class Thread implements Runnable {
// ThreadLocalMap是一個以ThreadLocal為key,Object為值的map,由ThreadLocal維護
ThreadLocal.ThreadLocalMap threadLocals = null;
}
從Thread的源碼中可以得知,是每一個Thread持有一個自己的map,并不是一個ThreadLocal持有一個map。
public class ThreadLocal<T> {
public T get() {
// 獲取當前線程
Thread t = Thread.currentThread();
// 獲取當前線程的threadLocals變量
ThreadLocalMap map = getMap(t);
// 從當前線程的threadLocals變量中取得本threadLocal為key的值
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
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;
}
public void set(T value) {
// 獲取當前線程
Thread t = Thread.currentThread();
// 獲取當前線程的threadLocals變量
ThreadLocalMap map = getMap(t);
// 以本threadLocal為key的保存值到當前線程的threadLocals變量中去
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
}
使用ThreadLocal過程: 對于每一個需要線程保存自身實例的變量,需要定義一個靜態的ThreadLocal實例。然后將一個共用的ThreadLocal靜態實例作為key,將不同對象的引用保存到不同線程的ThreadLocalMap中,然后在線程執行的各處通過這個靜態ThreadLocal實例的get()方法取得自己線程保存的那個對象。
此外,每個線程保存的自身數據并不是通過備份或復制的,而是new創建出來的。
通過ThreadLocal各個線程只能獲取自身對應的數據,不能訪問其他線程的數據,但是如果兩個線程在set時引用了同一個數據,仍然存在同步問題。
posted on 2011-03-31 14:05
liucs 閱讀(2841)
評論(0) 編輯 收藏 所屬分類:
多線程與并發