ThreadLocal的简单理解

一.基本介绍

谷歌开发文档上的介绍:Implements a thread-local storage, that is, a variable for which each thread has its own value. All threads share the sameThreadLocal object, but each sees a different value when accessing it, and changes made by one thread do not affect the other threads. The implementation supportsnull values.

中文意思是,实现了一个线程本地存储的功能,也就是说每个线程的相同的这个变量可以有不同的值,所有线程都用一个ThreadLocal对象,但是每个线程都能拿到不同的值,而且一个线程修改他的值不会影响其他线程中的值,这个值可以是null。

二.工作原理

ThreadLocal是一个线程内部的数据存储类,通过他可以在指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据。

(1).例子

public class MainActivity extends Activity {
    private ThreadLocal<Boolean> mBoolThreadLocal = new ThreadLocal<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mBoolThreadLocal.set(true);
        System.out.println("xcqw0-" + Thread.currentThread().getName() + "--" + mBoolThreadLocal.get());
        new Thread(){
            @Override
            public void run() {
                super.run();
                mBoolThreadLocal.set(false);
                System.out.println("xcqw1-"+Thread.currentThread().getName()+"--"+mBoolThreadLocal.get());
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                super.run();
                System.out.println("xcqw2-"+Thread.currentThread().getName()+"--"+mBoolThreadLocal.get());
            }
        }.start();
    }
}

结果:

System.out﹕ xcqw0-main--true
System.out﹕ xcqw1-Thread-428--false
System.out﹕ xcqw2-Thread-429--null(没有赋值,所以是Null

(2)工作原理

为啥访问同一个ThreadLocal的get方法,获取的值却不一样?一般都会有这样的疑问,不同的线程会根据不同的线程创建一个数据的载体Values(不同线程这个值肯定不一样),然后从中拿到数组和当前线程的索引,就可以获取对应的值,下面用源码验证一下。

  /**
     * Sets the value of this variable for the current thread. If set to
     * {@code null}, the value will be set to null and the underlying entry will
     * still be present.
     *
     * @param value the new value of the variable for the caller thread.
     */
    public void set(T value) {
        Thread currentThread = Thread.currentThread();
        Values values = values(currentThread);
        if (values == null) {
            values = initializeValues(currentThread);
        }
        values.put(this, value);
    }
Values values = values(currentThread);
可以看出在Thread类的内部有一个成员 专门用于存储线程的ThreadLocal的数据就是 Values values,如果为null就对其初始化,然后再把ThreadLocal对象的值传递进去。

 /**
     * Gets Values instance for this thread and variable type.
     */
    Values values(Thread current) {
        return current.localValues;
    }
Thread.java

  /**
     * Normal thread local values.
     */
    ThreadLocal.Values localValues;




 static class Values {

        /**
         * Size must always be a power of 2.
         */
        private static final int INITIAL_SIZE = 16;

        /**
         * Placeholder for deleted entries.
         */
        private static final Object TOMBSTONE = new Object();

     可以看出Valus内部有一个数组table

        /**
         * Map entries. Contains alternating keys (ThreadLocal) and values.
         * The length is always a power of 2.
         */
        private Object[] table;
<span style="white-space:pre">	</span>。。。。。
<span style="white-space:pre">	</span>。。。。。
}


 可下面是TheadLocal值得保存方法

 /**
         * Sets entry for given ThreadLocal to given value, creating an
         * entry if necessary.
         */
        void put(ThreadLocal<?> key, Object value) {
            cleanUp();

            // Keep track of first tombstone. That's where we want to go back
            // and add an entry if necessary.
            int firstTombstone = -1;

            for (int index = key.hash & mask;; index = next(index)) {
                Object k = table[index];

                if (k == key.reference) {
                    // Replace existing entry.
                    table[index + 1] = value;
                    return;
                }

                if (k == null) {
                    if (firstTombstone == -1) {
                        // Fill in null slot.
                        table[index] = key.reference;
                        table[index + 1] = value;
                        size++;
                        return;
                    }

                    // Go back and replace first tombstone.
                    table[firstTombstone] = key.reference;
                    table[firstTombstone + 1] = value;
                    tombstones--;
                    size++;
                    return;
                }

                // Remember first tombstone.
                if (firstTombstone == -1 && k == TOMBSTONE) {
                    firstTombstone = index;
                }
            }
        }
下最终ThreadLocal的值将会被存储到 table数组 中,table[index+1] = value

下面是ThreadLocal的get方法

  /**
     * Returns the value of this variable for the current thread. If an entry
     * doesn't yet exist for this variable on this thread, this method will
     * create an entry, populating the value with the result of
     * {@link #initialValue()}.
     *
     * @return the current value of the variable for the calling thread.
     */
    @SuppressWarnings("unchecked")
    public T get() {
        // Optimized for the fast path.
        Thread currentThread = Thread.currentThread();
        Values values = values(currentThread);
        if (values != null) {
            Object[] table = values.table;
            int index = hash & values.mask;
            if (this.reference == table[index]) {
                return (T) table[index + 1];
            }
        } else {
            values = initializeValues(currentThread);
        }

        return (T) values.getAfterMiss(this);
    }

总结:

从ThreadLocal的set和get方法可以看出,他们所操作的对象都是当前线程的localValues对象的table数据,因此在不同线程访问同一个ThreadLocal对象的get和set方法,他们对数据的读写操作都是发生在LocalValues(不同线程不一样)中,所有他们的操作都是在各自线程的内部, 这就是为什么TheadLocal可以在多个线程中可以互不干扰地存储和修改数据!



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值