카테고리 없음

[java] 자바 : 스레드 지역 목록?

행복을전해요 2020. 12. 30. 02:02

Listing ThreadLocals and Clearing ThreadLocals can be accomplished by using reflection (and the setAccessible() flag) to override the JVM's usual permissions. For obvious reasons, this not available when all security mechanisms are in place.

-------------------

You could use the afterExecute method of the thread pool to do whatever cleanup (reinitializiation?), as long as you know which variables you want to clean up.

Otherwise you could use reflection - from within the thread, iterate through the declared fields of the class(es) youre interested in, and for each one whose type is an instance of ThreadLocal, set it to its initialValue on the object(s) you care about.

-------------------

Along the lines of 'Another good way to do this', I made a Runnable wrapper which takes a snapshot of the pre-existing thread locals, runs the nested runnable, then clears (sets to null) any thread local which was not initially present.

This could be better done by putting the 'snapshot' code into a subclassed Executor's beforeExecute() and the 'cleanup' code in the afterExecute as suggested by @danben.

Either way, the beauty is that you don't have to hard-code which thread locals to keep or discard.

Exception handling was removed from the source listing to avoid clutter.

public class ThreadLocalCleaningRunnable implements Runnable
{
    private final Runnable runnable;
    
        public ThreadLocalCleaningRunnable(Runnable runnable) {
                this.runnable = nonNull(runnable);
                    }
                    
                        public void run() {
                            //  printThreadLocals();
                                    Set<ThreadLocal<?>> 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 < threadLocalCount; i++) {
                                                                                                                                                                                                                                                                                                                            Object entry = Array.get(table, i);
                                                                                                                                                                                                                                                                                                                                                    if (entry instanceof Reference) {
                                                                                                                                                                                                                                                                                                                                                                                Field valueField = entry.getClass().getDeclaredField("value");
                                                                                                                                                                                                                                                                                                                                                                                                            valueField.setAccessible(true);
                                                                                                                                                                                                                                                                                                                                                                                                                                        Object value = valueField.get(entry);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                    if (value != null) {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    System.err.print("thread ["+ threadName +"] local "+ value.getClass().getName() +" "+ value.toString());
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                public static Set<ThreadLocal<?>> getThreadLocalKeys() {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        Thread thread = Thread.currentThread();
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    Set<ThreadLocal<?>> threadLocalKeys = new HashSet<ThreadLocal<?>>();
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                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 < threadLocalCount; i++) {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        Object entry = Array.get(table, i);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                if (entry instanceof Reference) {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            Object o = ((Reference<?>) entry).get();
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        if (o instanceof ThreadLocal) {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        threadLocalKeys.add((ThreadLocal<?>) o);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        return threadLocalKeys;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                public static void cleanThreadLocalsExcept(Set<ThreadLocal<?>> 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 < threadLocalCount; i++) {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            Object entry = Array.get(table, i);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    if (entry instanceof Reference) {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                Object o = ((Reference<?>) 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);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
-------------------

The reason I need this is I need to inspect threads as they are returned to a thread pool to ensure the ThreadLocals have been properly cleaned up.

Personally, I think using thread local data on threadpool threads is a bad practice. If you really need thread local state, you should be self managing the threads, so you can explicitly cleanup the data.

Thread pool threads have indeterminate lifetimes, so you shouldn't be relying on explicitly managed local thread data.

-------------------

You could use AOP-like construct, by creating a Runnable implementation that wraps the original Runnable by your own implementation. It will invoke the original Runnable's run method and then perform any other cleanup you need from within the thread's context, which will allow you to call the ThreadLocal.remove() method. Then, give this wrapper to the thread pool. This would work for any thread pool implementation (e.g. ones without before/afterExecute methods)

-------------------

출처에서 보면 꽤 빡빡한 것 같습니다. 모든 것은 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 바이트 코드를 패치해야합니다. 나중에 리플렉션을 사용하여 메서드를 호출 할 수 있도록 메서드에 대한 핸들을 가져와야합니다.

참고 : 보안 메커니즘이 일반적으로 시스템 클래스를 조작하는 것을 방지하므로 제한된 환경 (애플릿 또는 앱 서버)에서 실행중인 경우에는 작동하지 않을 수 있습니다.



출처
https://stackoverflow.com/questions/2002786