QT的QStyle類的使用
多個執行緒需要對一個共享變數寫入時容易出現併發問題。
ThreadLocal可以做到:當多個執行緒對一個共享變數進行訪問的時候,實際上訪問的是本執行緒的本地變數。
一、ThreadLocal實現原理
Thread類中有threadlocals變數,threadlocals變數的型別是ThreadLocal.ThreadLocalMap,是在ThreadLocal類中實現的一個類似於Map的結構,ThreadLocalMap結構實際上是一個Entry對,key值是ThreadLocal物件,value值是ThreadLocal物件的值,如下圖所示:
二、ThreadLocal實現細節
1、get實現
public T get() { //獲取當前執行緒 Thread t = Thread.currentThread(); //獲取當前執行緒的threadLocals變數 ThreadLocalMap map = getMap(t); //如果當前執行緒的threadLocals變數不為空,則返回對應的value值 if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } //如果當前執行緒threadLocals變數為null,則初始化當前執行緒的threadLocals變數 return setInitialValue(); }
private T setInitialValue() { //定義value = null T value = initialValue(); //獲取當前執行緒 Thread t = Thread.currentThread(); //獲取當前執行緒的threadLocals變數 ThreadLocalMap map = getMap(t); //如果當前執行緒的threadLocals變數不為空,則將當前的threadLocals變數的value值置為null if (map != null) map.set(this, value); //如果當前執行緒的threadLocals變數為空,則初始化建立一個當前執行緒的threadLocals變數,並將value置為null else createMap(t, value); return value; }
2、set實現
public void set(T value) {
//獲取當前執行緒
Thread t = Thread.currentThread();
//獲取當前執行緒的threadLocals變數
ThreadLocalMap map = getMap(t);
//如果當前執行緒的threadLocals變數不為空,則將該變數的value值設定為傳入的value值
if (map != null)
map.set(this, value);
//如果當前執行緒的threadLocals變數為空,則初始化建立一個當前執行緒的threadLocals變數,並將該變數的value值設定為傳入的value值
else
createMap(t, value);
}
3、remove實現
public void remove() {
//獲取當前執行緒的threadLocals變數
ThreadLocalMap m = getMap(Thread.currentThread());
//如果不為空,則刪除當前執行緒中指定ThreadLocal例項的本地變數
if (m != null)
m.remove(this);
}
三、記憶體洩露
我們先看看ThreadLocal態類裡面的成員:
public class ThreadLocal<T>{
//......
static class ThreadLocalMap{
static class Entry extends WeakReference<ThreadLocal<?>>{
Object value;
Entry(ThreadLocal<?> k, Object v){
super(k);
value = v;
}
}
//......
}
//......
}
當一個執行緒呼叫ThreadLocal類的set方法設定當前執行緒的本地變數時,當前執行緒的ThreadLocalMap中會有一條記錄,該記錄的key值為ThreadLocal的弱引用,value為set方法設定的值。
如果當前執行緒一直存在,且沒有呼叫ThreadLocal的remove方法,且這時候還有其他地方還有對ThreadLocal的引用,則當前執行緒的ThreadLocalMap變數裡會同時存在對ThreadLocal變數的引用和對value物件的引用,它們不會被釋放,因此會造成記憶體洩露。
由於執行緒的ThreadLocalMap中的key是弱引用,所以當前執行緒的ThreadLocalMap中的ThreadLocal變數的弱引用會在下一次gc時被回收,但是對應的value還是會造成記憶體洩露,這時候ThreadLocalMap中會存在key為null但是value不為null的Entry項。
解決方法:在每次使用完畢後呼叫remove方法。