Thread-Specific Storage
January 13, 2022為了管理名稱,程式語言會有名稱空間概念,例如,視語言的不同,變數可能會有不同的範疇,像是區塊變數、區域變數、類別變數、物件值域、模組變數、全域變數等。
如果想以執行緒作為名稱空間呢?
執行緒專用空間
你可以使用 Map
之類的結構,以執行緒為鍵,儲存對應的物件,設計一個簡單的 ThreadLocal
類別:
class ThreadLocal<T> {
private Map<Thread, T> storage = Collections.synchronizedMap(new WeakHashMap<>());
T get() {
return storage.get(Thread.currentThread());
}
void set(T value) {
storage.put(Thread.currentThread(), value);
}
void remove() {
storage.remove(Thread.currentThread());
}
}
在 Thread
生命週期結束,被 JVM 回收之後,對應的資源也應當被移除,因此這邊使用了 WeakHashMap
,作為 Thread
的鍵被回收後,對應的鍵/值也會從 WeakHashMap
移除。
ThreadLocal
實例通常作為 static
成員存在,例如,設計一個 ThreadScope
:
class ThreadScope {
private static final ThreadLocal<Map<String, Object>> scopes = new ThreadLocal<>();
static Map<String, Object> get() {
var scope = scopes.get();
if(scope == null) {
scope = new HashMap<>();
scopes.set(scope);
}
return scope;
}
}
這麼一來,想以執行緒作為名稱空間,設置新的變數與值,就可以如下:
ThreadScope.get().put("connectionId", 1);
想取得某執行緒名稱空間中的變數就可以如下:
ThreadScope.get().get("connectionId");
執行緒/資源
Thread-Specific Storage 就是以執行緒為單位,儲存對應的資源,方才只是以名稱空間為例,實際上是為每個執行緒儲存對應的 HashMap
。
這類應用也可以用來做資源快取,例如:
public class Resource {
private static final ThreadLocal<Resource> resources = new ThreadLocal<>();
public static Resource getResource() {
var resource = resources.get();
if(resource == null) {
resource = new Resource();
resources.set(resource);
}
return resource;
}
}
支援多執行緒環境的語言,多半會有 Thread-Specific Storage 的方案,例如 Java 標準 API 就提供了 java.lang.ThreadLocal
可以使用。