0
点赞
收藏
分享

微信扫一扫

ThreadLocal的使用和解析

40dba2f2a596 2022-03-27 阅读 26
java

整体实现解析

ThreadLocal和Sychronized都用于解决多线程并发访问的问题。sychronized利用锁机制使的变量或代码块在某一时刻仅仅被一个线程访问。而ThreadLoal为每个线程提供threadlocal变量的副本,使得每个线程某一时刻访问到的并非同一个对象,从而隔离多个线程对数据的共享。
在这里插入图片描述
每个线程有自己的一个ThreadLocalMap对象,ThreadLocalMap对象里面有一个Entry数组,用于存放需要用到的value。而每个Entry里面的value通过类里面new出来的ThreadLocal对象作为key取得。

ThreadLocal的使用

/**
 * ThreadLocal的使用
 * Created by linshujie on 2022/3/25.
 */
public class UseThreadLocal {
    private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return 1;
        }
    };

    /**
     * 运行3个线程
     */
    public void startThreadArray() {
        Thread[] runs = new Thread[3];
        for (int i = 0; i < runs.length; i++) {
            runs[i] = new Thread(new TestThread(i));
        }
        for (int i = 0; i < runs.length; i++) {
            runs[i].start();
        }
    }

    /**
     * 测试线程,线程的工作是将ThreadLocal变量的值变化,并写回,看看线程之间是否会互相影响
     */
    public static class TestThread implements Runnable {
        int id;

        public TestThread(int id) {
            this.id = id;
        }

        public void run() {
            System.out.println(Thread.currentThread().getName() + ":start");
            Integer initialValue = threadLocal.get();
            initialValue = initialValue + id;
            threadLocal.set(initialValue);
            System.out.println(Thread.currentThread().getName()
                    + ":" + threadLocal.get());
            threadLocal.remove();
        }
    }

    public static void main(String[] args) {
        UseThreadLocal test = new UseThreadLocal();
        test.startThreadArray();
    }
}

通过get方法获取当前线程的ThreadLocalMap

/**
     * Returns the value in the current thread's copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     *
     * @return the current thread's value of this thread-local
     */
    public T get() {
        Thread t = Thread.currentThread();
        //传入当前线程,拿到当前线程的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null) {
        //把ThreadLocal作为key
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }

返回当前线程中threadlocal变量的副本,如果threadlocal变量没有位于当前线程的值,它会通过调用initialValue方法来进行初始化。

   /**
     * Get the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param  t the current thread
     * @return the map
     */
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

通过传入的当前线程来获取它绑定的ThreadLocalMap

先获取当前线程,然后调用getMap方法获取对应的ThreadLocalMap。其中ThreadLocalMap是ThreadLocal的静态内部类,Thread中有一个ThreadLocalMap成员变量,所以getMap是直接获取Thread的成员变量ThreadLocalMap。

通过getEntry方法获取ThreadLocalMap中的Entry

   /**
         * Get the entry associated with key.  This method
         * itself handles only the fast path: a direct hit of existing
         * key. It otherwise relays to getEntryAfterMiss.  This is
         * designed to maximize performance for direct hits, in part
         * by making this method readily inlinable.
         *
         * @param  key the thread local object
         * @return the entry associated with key, or null if no such
         */
        private Entry getEntry(ThreadLocal key) {
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            if (e != null && e.get() == key)
                return e;
            else
                return getEntryAfterMiss(key, i, e);
        }

回顾get方法中的代码:ThreadLocalMap.Entry e = map.getEntry(this);把当前new出来的ThreadLocal对象作为key,获取Entry。

 /**
     * ThreadLocalMap is a customized hash map suitable only for
     * maintaining thread local values. No operations are exported
     * outside of the ThreadLocal class. The class is package private to
     * allow declaration of fields in class Thread.  To help deal with
     * very large and long-lived usages, the hash table entries use
     * WeakReferences for keys. However, since reference queues are not
     * used, stale entries are guaranteed to be removed only when
     * the table starts running out of space.
     */
    static class ThreadLocalMap {

        /**
         * 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;

			//类似于map的key、value结构,key是ThreadLocal,value是需要被隔离的变量
            Entry(ThreadLocal k, Object v) {
                super(k);
                value = v;
            }
        }

        /**
         * The initial capacity -- MUST be a power of two.
         */
        private static final int INITIAL_CAPACITY = 16;

        /**
         * The table, resized as necessary.
         * table.length MUST always be a power of two.
         */
         //可能有多个需要被隔离的变量,用数组保存
        private Entry[] table;

通过get方法拿到每个线程独有的ThreadLocalMap,然后用ThreadLocal的当前实例作为key去拿到ThreadLocalMap中的Entry,拿到Entry,那么Entry中的value就可以得到了。value就是我们调用

    private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return 1;
        }
    };

返回的值。

举报

相关推荐

0 条评论