A. ThreadLocal問題 當前線程中的ThreadLocalMap變數哪來的
t.threadLocals 是當前線程Thread(t) 的成員變數, 當使用 ThreadLocal 創建對象後,調用 ThreadLocal.set()方法會看到初始化 ThreadLocalMap的過程,JDK內部實現代碼截圖如下:
(1)調用set方法,初始化 ThreadLocalMap 對象,如果getMap(t)獲取當前線程 threadLocals 變數為空,隨後創建一個;反之,直接使用存儲線程數據.
B. 什麼是threadlocal變數
ThreadLocal變數就是和線程綁定的變數.實際上是一個Map,,,key是對應的線程,值則是該變數. 調用ThreadLocal的get方法時則會到Map中查詢當前線程是否已擁有該變數,如果沒有則新建一個並保存到Map中.有的話直接返回與該線程綁定的變數. 說白了就是
C. ThreadLocal如何保證獲取到想要線程變數
首先ThreadLocal並不會存儲數據,它做的只是做獲取和存放這些過程.數據本身並沒有存在ThreadLocal中.
那麼問題來了,數據到底存放在哪裡?
存放在當前線程中即Thread中的ThreadLocalMap中.
那麼ThreadLocalMap又是什麼?
ThreadLocal的內部類.....,事實就是這樣
那麼ThreadLocal 是線程安全的嗎?
一般意義上講ThreadLocal是線程安全的,因為你操作的只是你自己的線程變數....
在其他線程中可不可以獲取當前線程變數?
可以...你可以通過反射機制,加上線程對象...你操作操作...這下就不安全啦...
D. threadlocalmap為什麼需要存儲多個entry
dLocalMap threadlocalmap = getMap(thread); if(threadlocalmap != null) { ThreadLocalMap.Entry entry = threadlocalmap.getEntry(this); if(entry != null)
E. ThreadLocal一般用在哪些地方有何用
從如下8點來講解一下:
1.ThreadLocal用來解決多線程程序的並發問題
2.ThreadLocal並不是一個Thread,而是Thread的局部變數,當使用ThreadLocal維護變數時,ThreadLocal為每個使用該變數的線程提供獨立的變數副本,所以每個線程都
可以獨立地改變自己的副本,而不會影響其它線程所對應的副本.
3.從線程的角度看,目標變數就象是線程的本地變數,這也是類名中「Local」所要表達的意思。
4.線程局部變數並不是Java的新發明,Java沒有提供在語言級支持(語法上),而是變相地通過ThreadLocal的類提供支持.
5.ThreadLocal類中的方法:(JDK5版本之後支持泛型)
void set(T value)
將此線程局部變數的當前線程副本中的值設置為指定值
void remove()
移除此線程局部變數當前線程的值
protected T initialValue()
返回此線程局部變數的當前線程的「初始值」
T get()
返回此線程局部變數的當前線程副本中的值
6.ThreadLocal的原理:
ThreadLocal是如何做到為每一個線程維護變數的副本的呢?其實實現的思路很簡單:在ThreadLocal類中有一個Map,用於存儲每一個線程的變數副本,Map中元素
的鍵為線程對象,而值對應線程的變數副本
7.自己模擬ThreadLocal:
public class SimpleThreadLocal{
private Map valueMap=Collections.synchronizedMap(new HashMap());
public void set(Object newValue){
valueMap.put(Thread.currentThread(),newValue);//鍵為線程對象,值為本線程的變數副本
}
F. Java:ThreadLocal究竟有什麼用呢費解
從如下8點來講解一下:
1.ThreadLocal用來解決多線程程序的並發問題
2.ThreadLocal並不是一個Thread,而是Thread的局部變數,當使用ThreadLocal維護變數時,ThreadLocal為每個使用該變數的線程提供獨立的變數副本,所以每個線程都
可以獨立地改變自己的副本,而不會影響其它線程所對應的副本.
3.從線程的角度看,目標變數就象是線程的本地變數,這也是類名中「Local」所要表達的意思。
4.線程局部變數並不是Java的新發明,Java沒有提供在語言級支持(語法上),而是變相地通過ThreadLocal的類提供支持.
5.ThreadLocal類中的方法:(JDK5版本之後支持泛型)
void set(T value)
將此線程局部變數的當前線程副本中的值設置為指定值
void remove()
移除此線程局部變數當前線程的值
protected T initialValue()
返回此線程局部變數的當前線程的「初始值」
T get()
返回此線程局部變數的當前線程副本中的值
6.ThreadLocal的原理:
ThreadLocal是如何做到為每一個線程維護變數的副本的呢?其實實現的思路很簡單:在ThreadLocal類中有一個Map,用於存儲每一個線程的變數副本,Map中元素
的鍵為線程對象,而值對應線程的變數副本
7.自己模擬ThreadLocal:
public class SimpleThreadLocal{
private Map valueMap=Collections.synchronizedMap(new HashMap());
public void set(Object newValue){
valueMap.put(Thread.currentThread(),newValue);//鍵為線程對象,值為本線程的變數副本
}
public Object get(){
ThreadcurrentThread=Thread.currentThread();
Object o=valueMap.get(currentThread);//返回本線程對應的變數
if(o==null&&!valueMap.containsKey(currentThread)){
//如果在Map中不存在,放到Map中保存起來
o=initialValue();
valueMap.put(currentThread,o);
}
return o;
}
public void remove(){
valueMap.remove(Thread.currentThread());
}
public void initialValue(){
return null;
}
}
8.使用ThreadLocal的具體例子:
public class SequenceNumber{
//通過匿名內部類覆蓋ThreadLocal的initialValue()方法,指定初始值
private static ThreadLocal<Integer> seNum=new ThreadLocal<Integer>(){
protected Integer initialValue(){
return 0;
}
}
public Integer getNextNum(){
seNum.set(seNum.get()+1);
return seNum.get();
}
public static void main(String[] args){
SequenceNumber sn=new SequenceNumber();
//3個線程共享sn,各自產生序列號
TestClient t1 = new TestClient(sn);
TestClient t2 = new TestClient(sn);
TestClient t3 = new TestClient(sn);
t1.start();
t2.start();
t3.start();
}
private static class TestClient extends Thread{
private SequenceNumber sn;
public TestClient(SequenceNumber sn){
this.sn=sn;
}
public void run(){
//每個線程列印3個序列號
for(int i=0;i<3;i++){
System.out.println("thread["+Thread.currentThread().getName()+",sn["+sn.getNextNum()+"]");
}
}
}
}
G. 如何避免threadlocal內存泄露
threadlocal裡面使用了一個存在弱引用的map,當釋放掉threadlocal的強引用以後,map裡面的value卻沒有被回收.而這塊value永遠不會被訪問到了. 所以存在著內存泄露. 最好的做法是將調用threadlocal的remove方法.
在threadlocal的生命周期中,都存在這些引用. 看下圖: 實線代表強引用,虛線代表弱引用.每個thread中都存在一個map, map的類型是ThreadLocal.ThreadLocalMap. Map中的key為一個threadlocal實例. 這個Map的確使用了弱引用,不過弱引用只是針對key. 每個key都弱引用指向threadlocal. 當把threadlocal實例置為null以後,沒有任何強引用指向threadlocal實例,所以threadlocal將會被gc回收. 但是,我們的value卻不能回收,因為存在一條從current thread連接過來的強引用. 只有當前thread結束以後, current thread就不會存在棧中,強引用斷開, Current Thread, Map, value將全部被GC回收.
所以得出一個結論就是只要這個線程對象被gc回收,就不會出現內存泄露,但在threadLocal設為null和線程結束這段時間不會被回收的,就發生了我們認為的內存泄露。其實這是一個對概念理解的不一致,也沒什麼好爭論的。最要命的是線程對象不被回收的情況,這就發生了真正意義上的內存泄露。比如使用線程池的時候,線程結束是不會銷毀的,會再次使用的。就可能出現內存泄露。
PS.Java為了最小化減少內存泄露的可能性和影響,在ThreadLocal的get,set的時候都會清除線程Map里所有key為null的value。所以最怕的情況就是,threadLocal對象設null了,開始發生「內存泄露」,然後使用線程池,這個線程結束,線程放回線程池中不銷毀,這個線程一直不被使用,或者分配使用了又不再調用get,set方法,那麼這個期間就會發生真正的內存泄露。
H. 什麼是 ThreadLocal 類ThreadLocal 是一個線程級別的局部變數如何理解
ThreadLocal變數就是和線程綁定的變數.實際上是一個Map,,,key是對應的線程,值則是該變數.
調用ThreadLocal的get方法時則會到Map中查詢當前線程是否已擁有該變數,如果沒有則新建一個並保存到Map中.有的話直接返回與該線程綁定的變數.
說白了就是每個線程擁有不同的實例.以空間換時間.
I. spring的事務對象是存儲在哪裡的
Spring的事物相關對象是在ThreadLocal中保存,並在事物結束時清空的。