Java学习笔记——ThreadLocal类的使用

Posted douglasdoudou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java学习笔记——ThreadLocal类的使用相关的知识,希望对你有一定的参考价值。

主要是对博客的一些自己的理解和补充  地址:http://www.cnblogs.com/-new/p/7604420.html

概述:

  这里套用该博主的实验代码:

   

public class T {
    ThreadLocal<Long> longLocal = new ThreadLocal<Long>();
    public void set() {
        longLocal.set(Thread.currentThread().getId());
    }
    public long getLong() {
        return longLocal.get();
    }
    public static void main(String[] args) throws InterruptedException {
        final T test = new T();
        test.set();
        Thread thread1 = new Thread(){
            public void run() {
                test.set();
                System.out.println("线程一:"+test.getLong());
            };
        };
        thread1.start();
        thread1.join();
        System.out.println("main线程:"+test.getLong());
        System.out.println("没有发生值的覆盖,两个线程保存的值是不同的");
    }
}

  1、基本分析

  • 对于主线程和thread1两个线程来说,他们共享了T类的test这个对象,这个时候两者可以通过ThreadLocal类来分别保存一个test对象里面的值;也就是说:test对象不变,但是里面有一个变量是因使用test这个对象不同而不同的,longLocal变量就是这个变量
  • 它的底层是使用一个ThreadLocalMap来实现的(每一个Thread里面都有这个对象),里面的Entry键名为某一个对象的ThreadLocal的实例,键值为具体的值,一个线程可以绑定多个ThreadLocal对象; 并且,Thread对象的成员ThreadLocalMap是懒加载的,用到的时候才加载:(注意:这里的threadLocals是线程t的一个成员变量ThreadLocalMap的实例)
     /**
         * Create the map associated with a ThreadLocal. Overridden in
         * InheritableThreadLocal.
         *
         * @param t the current thread
         * @param firstValue value for the initial entry of the map
         */
        void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }

    这里是使用ThreadLocal对象的实例作为Entry的键名

    /**
             * Construct a new map initially containing (firstKey, firstValue).
             * ThreadLocalMaps are constructed lazily, so we only create
             * one when we have at least one entry to put in it.
             */
            ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
                table = new Entry[INITIAL_CAPACITY];
                int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
                table[i] = new Entry(firstKey, firstValue);
                size = 1;
                setThreshold(INITIAL_CAPACITY);
            }

    这里是set方法的源码,使用的是开地址法

     /**
             * Set the value associated with key.
             *
             * @param key the thread local object
             * @param value the value to be set
             */
            private void set(ThreadLocal<?> key, Object value) {
    
                // We don‘t use a fast path as with get() because it is at
                // least as common to use set() to create new entries as
                // it is to replace existing ones, in which case, a fast
                // path would fail more often than not.
    
                Entry[] tab = table;
                int len = tab.length;
                int i = key.threadLocalHashCode & (len-1);
    
                for (Entry e = tab[i];
                     e != null;
                     e = tab[i = nextIndex(i, len)]) {
                    ThreadLocal<?> k = e.get();
    
                    if (k == key) {
                        e.value = value;
                        return;
                    }
    
                    if (k == null) {
                        replaceStaleEntry(key, value, i);
                        return;
                    }
                }
    
                tab[i] = new Entry(key, value);
                int sz = ++size;
                if (!cleanSomeSlots(i, sz) && sz >= threshold)
                    rehash();
            }

     

    2、可能存在的问题:内存泄漏
     注意:由于ThreadLocal.ThreadLocalMap.Entry继承自弱连接,当强连接断了之后,下一次GC就可以释放键名ThreadLocal对象的内存。 但是,value:在ThreadLocal.ThreadLocalMap.Entry中使用的强连接,无法由程序自动GC,必须通过remove、set、get等方法触发GC
    /**
             * The entries in this hash map extend WeakReference, using
             * its main ref field as the key (which is always a
             * ThreadLocal object).  Note that null keys (i.e. entry.get()
             * == null) mean that the key is no longer referenced, so the
             * entry can be expunged from table.  Such entries are referred to
             * as "stale entries" in the code that follows.
             */
            static class Entry extends WeakReference<ThreadLocal<?>> {
                /** The value associated with this ThreadLocal. */
                Object value;
    
                Entry(ThreadLocal<?> k, Object v) {
                    super(k);
                    value = v;
                }
            }

     

    ps:第一次写博客,写的也只是自己的一些心得体会,有什么不足之处欢迎指出

以上是关于Java学习笔记——ThreadLocal类的使用的主要内容,如果未能解决你的问题,请参考以下文章

ThreadLocal学习笔记

ThreadLocal学习笔记

ThreadLocal学习笔记

经典干货《Java 多线程编程核心技术》学习笔记及总结(中)

Java面试题必备知识之ThreadLocal

java笔记java中ThreadLocal的原理和使用