有沒有辦法列出綁定到線程的TheadLocals?理想情況下,我可以訪問Thread.threadLocals地圖,但它受到封裝保護。java:list thread locals?
我需要這個的原因是我需要檢查線程,因爲它們返回到線程池以確保ThreadLocals已被正確清理。也許還有另一種方式來做到這一點?
有沒有辦法列出綁定到線程的TheadLocals?理想情況下,我可以訪問Thread.threadLocals地圖,但它受到封裝保護。java:list thread locals?
我需要這個的原因是我需要檢查線程,因爲它們返回到線程池以確保ThreadLocals已被正確清理。也許還有另一種方式來做到這一點?
只要您知道要清理哪些變量,您可以使用線程池的afterExecute
方法來執行任何清理(重新初始化?)。
否則,您可以使用反射 - 從線程內,遍歷您感興趣的類的聲明字段,併爲每個類型爲ThreadLocal的實例的0123.set
對該對象的initialValue
(s)你在乎。
我需要這個的原因是我需要檢查線程,因爲它們返回到線程池以確保ThreadLocals已被正確清理。
就我個人而言,我認爲在線程池線程上使用線程本地數據是一種不好的做法。如果你真的需要線程本地狀態,你應該自己管理線程,所以你可以明確地清理數據。
線程池線程具有不確定的生命週期,所以您不應該依賴顯式管理的本地線程數據。
您可以使用類AOP構造,通過創建一個Runnable實現,該實現通過您自己的實現來包裝原始的Runnable。它將調用原始的Runnable的run方法,然後在線程的上下文中執行所需的其他清理,這將允許您調用ThreadLocal.remove()方法。然後,給這個包裝到線程池。這適用於任何線程池實現(例如沒有before/afterExecute方法的實現)
掛鉤到線程生命週期不是問題。我正在使用ThreadPoolExecutor,所以我有afterExecute方法來處理。問題給出了一個線程,我如何枚舉線程本地存儲?我想檢查它是否爲空,並且如果不記錄警告。 – 2010-01-04 19:51:12
你是否可以控制線程本地使用(你能告訴開發者使用你自己的實現)嗎?您可能能夠擴展ThreadLocal以幫助實現您的目標。 – Armadillo 2010-01-06 15:44:11
從源代碼看,它看起來非常緊密。一切對於Thread或ThreadLocal都是私有的。
您可能能夠通過重新定義ThreadLocal來添加一個方法,該方法將在當前線程上轉儲局部變量,從而通過工具代理執行您所需要的操作。
這裏有一個例子,我發現添加記錄到現有的類:http://today.java.net/pub/a/today/2008/04/24/add-logging-at-class-load-time-with-instrumentation.html
你需要使用BCEL或JavaAssist修補ThreadLocal的字節碼來添加方法。稍後,您需要使用反射來獲取方法的句柄,以便您可以調用它。
注:這個,如果你在一個受限制的環境(applet或應用服務器)作爲安全機制通常阻止你擺弄系統類運行可能不會工作。
Listing ThreadLocals和Clearing ThreadLocals可以通過使用反射(和the setAccessible() flag)來覆蓋JVM的常規權限來完成。出於顯而易見的原因,這在所有安全機制到位時都不可用。
沿着'另一個很好的方式來做到這一點',我做了一個Runnable包裝器,該包裝器獲取預先存在的線程本地的快照,運行嵌套的runnable,然後清除(設置爲null)任何線程local最初並不存在。
這可以通過將'快照'代碼放置到@Explorer中的beforeExecute()和'cleanup'代碼中來完成,就像@danben建議的那樣。
無論哪種方式,美麗的是,你不必硬編碼當地人保留或丟棄哪些線程。
異常處理已從源代碼清單中刪除以避免混亂。
public class ThreadLocalCleaningRunnable implements Runnable
{
private final Runnable runnable;
public ThreadLocalCleaningRunnable(Runnable runnable) {
this.runnable = nonNull(runnable);
}
public void run() {
// printThreadLocals();
Set> initialThreadLocalKeys = getThreadLocalKeys();
try {
runnable.run();
}
finally {
cleanThreadLocalsExcept(initialThreadLocalKeys);
// printThreadLocals();
}
}
public static void printThreadLocals() {
Thread thread = Thread.currentThread();
Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
Class threadLocalMapKlazz = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tableField = threadLocalMapKlazz.getDeclaredField("table");
tableField.setAccessible(true);
Object threadLocals = threadLocalsField.get(thread);
if (threadLocals != null) {
Object table = tableField.get(threadLocals);
if (table != null) {
int threadLocalCount = Array.getLength(table);
String threadName = thread.getName();
for (int i = 0; i > getThreadLocalKeys() {
Thread thread = Thread.currentThread();
Set> threadLocalKeys = new HashSet>();
Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
Class threadLocalMapKlazz = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tableField = threadLocalMapKlazz.getDeclaredField("table");
tableField.setAccessible(true);
Object threadLocals = threadLocalsField.get(thread);
if (threadLocals != null) {
Object table = tableField.get(threadLocals);
if (table != null) {
int threadLocalCount = Array.getLength(table);
for (int i = 0; i) entry).get();
if (o instanceof ThreadLocal) {
threadLocalKeys.add((ThreadLocal) o);
}
}
}
}
}
return threadLocalKeys;
}
public static void cleanThreadLocalsExcept(Set> keptThreadLocalKeys) {
Thread thread = Thread.currentThread();
Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
Class threadLocalMapKlazz = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tableField = threadLocalMapKlazz.getDeclaredField("table");
tableField.setAccessible(true);
Object threadLocals = threadLocalsField.get(thread);
if (threadLocals != null) {
Object table = tableField.get(threadLocals);
if (table != null) {
int threadLocalCount = Array.getLength(table);
for (int i = 0; i) entry).get();
if (o instanceof ThreadLocal) {
ThreadLocal tl = (ThreadLocal) o;
if (!keptThreadLocalKeys.contains(tl)) {
Field valueField = entry.getClass().getDeclaredField("value");
valueField.setAccessible(true);
valueField.set(entry, null);
}
}
}
}
}
}
}
}
同意。但我想修復現有代碼中的錯誤,而不是重新設計它。 – 2010-01-04 18:59:06