`
貌似掉线
  • 浏览: 260090 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Android中的ThreadLocal源码解析

阅读更多
我在之前的文章《Android中的Looper,Handler及HandlerThread简析》(http://maosidiaoxian.iteye.com/blog/1927735)中有提到过ThreadLocal,后来一直想详细读读这个类。前几天写完了Java原生的ThreadLocal,今天来看一下Android中的ThreadLocal类。在读这篇文章之前,建议先读一下我前面写的关于Java中的ThreadLocal解析的两篇文章,因为在这里对一些相同的内容我会不再赘述。

Android中的ThreadLocal的源码在libcore/luni/src/main/java/java/lang目录下,如果你没有下载Android源码,可通过以下地址读到该类的源码:https://android.googlesource.com/platform/libcore/+/android-4.3_r2.2/luni/src/main/java/java/lang/ThreadLocal.java
在Android中,ThreadLocal像是对原来的ThreadLcal做了优化的实现。我们同样先看看这个类的结构,如下图:





可以直观地看到在android中ThreadLocal比java原生的这个类少了一些API,而且保存线程变量的内部类名字也改为Values,里面没有再定义内部类。仔细地阅读比较,我们可以看到Android中对Java原生的ThreadLocal做了一些优化的工作。
先来看看ThreadLocal的变量,代码如下:
    /** Weak reference to this thread local instance. */
    private final Reference<ThreadLocal<T>> reference
            = new WeakReference<ThreadLocal<T>>(this);

    /** Hash counter. */
    private static AtomicInteger hashCounter = new AtomicInteger(0);

    /**
     * Internal hash. We deliberately don't bother with #hashCode().
     * Hashes must be even. This ensures that the result of
     * (hash & (table.length - 1)) points to a key and not a value.
     *
     * We increment by Doug Lea's Magic Number(TM) (*2 since keys are in
     * every other bucket) to help prevent clustering.
     */
    private final int hash = hashCounter.getAndAdd(0x61c88647 * 2);
在这里,ThreadLocal没有再定义HASH_INCREMENT 这个常量,而是直接写在了hash变量的定义当中。将原来的nextHashCode的代码与hash的定义合在了一起,增量则是0x61c88647 * 2。
在这里还多定义了一个变量,Reference<ThreadLocal<T>> reference,它是一个弱引用,引用ThreadLocal实例的自己。
而当实例化一个ThreadLocal对象时,仅仅是生成一个hash值,和对reference赋值。
在set方法中,依然是从线程中取得保存变量的对象,在这里是values,如果values为null就进行初始化(对thread对象创建Values对象并返回),然后调用其put方法保存变量,与Java原生的思路都是一样的,只是代码简化了许多,如下:
    public void set(T value) {
        Thread currentThread = Thread.currentThread();
        Values values = values(currentThread);
        if (values == null) {
            values = initializeValues(currentThread);
        }
        values.put(this, value);
    }

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

    /**
     * Creates Values instance for this thread and variable type.
     */
    Values initializeValues(Thread current) {
        return current.localValues = new Values();
    }


remove()方法就不谈了,很简单,跟原来的基本一致。
下面来看一下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);
    }

我们会注意到其中的代码:
            if (this.reference == table[index]) {
                return (T) table[index + 1];
            }

为什么用hash取得下标后,下一位才是保存的变量值呢?
我们来看一下Values这个类是怎么定义和设计的。
Values是被设计用来保存线程的变量的一个类,它相当于一个容器,存储保存进来的变量。它的成员变量如下:
        /**
         * Map entries. Contains alternating keys (ThreadLocal) and values.
         * The length is always a power of 2.
         */
        private Object[] table;

        /** Used to turn hashes into indices. */
        private int mask;

        /** Number of live entries. */
        private int size;

        /** Number of tombstones. */
        private int tombstones;

        /** Maximum number of live entries and tombstones. */
        private int maximumLoad;

        /** Points to the next cell to clean up. */
        private int clean;

同样table是实际上保存变量的地方,但它在这里是个Object类型的数组,它的长度必须是2的n次方的值。mask即计算下标的掩码,它的值是table的长度-1。size表示存放进来的实体的数量。这与前面原生的ThreadLocal的ThreadLocalMap是一样的。但是在这里它还定义了三个int类型的变量:tombstones表示被删除的实体的数量,maximumLoad是一个阈值,用来判断是否需要进行rehash,clean表示下一个要进行清理的位置点。
我们来看一下当Values对象被创建时进行了什么工作,代码如下:
        /**
         * Constructs a new, empty instance.
         */
        Values() {
            initializeTable(INITIAL_SIZE);
            this.size = 0;
            this.tombstones = 0;
        }

        /**
         * Creates a new, empty table with the given capacity.
         */
        private void initializeTable(int capacity) {
            this.table = new Object[capacity * 2];
            this.mask = table.length - 1;
            this.clean = 0;
            this.maximumLoad = capacity * 2 / 3; // 2/3
        }

上面的代码我们可以看到,当初始化一个Values对象时,它会创建一个长度为capacity*2的数组。
然后在add()方法当中,也可以看到它会把ThreadLocal对象(key)和对应的value放在连续的位置中。
        /**
         * Adds an entry during rehashing. Compared to put(), this method
         * doesn't have to clean up, check for existing entries, account for
         * tombstones, etc.
         */
        void add(ThreadLocal<?> key, Object value) {
            for (int index = key.hash & mask;; index = next(index)) {
                Object k = table[index];
                if (k == null) {
                    table[index] = key.reference;
                    table[index + 1] = value;
                    return;
                }
            }
        }

也就是table被设计为下标为0,2,4...2n的位置存放key,而1,3,5...(2n +1 )的位置存放value。直接通过下标存取线程变量,它比用WeakReference<ThreadLocal>类在内存占用上更经济,性能也更好。这也是前面中hash的增量要取0x61c88647*2的原因,它也保证了其二进制中最低位为0,也就是在计算key的下标时,一定是偶数位。
而在remove()方法中,移除变量时它是把对应的key的位置赋值为TOMBSTONE,value赋值为null,然后 tombstones++;size--;。TOMBSTONE是前面定义的一个常量,表示被删除的实体。
其他方法的算法,其实与Java原生的一样,只是做了对应于Values类的设计的修改。这里不再赘述。
  • 大小: 9.5 KB
  • 大小: 13.4 KB
0
1
分享到:
评论
2 楼 貌似掉线 2013-09-12  
xiaozhi6156 写道
不明觉历,回家再看..LZ加油

==!
1 楼 xiaozhi6156 2013-09-12  
不明觉历,回家再看..LZ加油

相关推荐

    ThreadLocal源码(版本:Android4.3,,含注释)

    ThreadLocal源码(版本:Android4.3,,含注释)

    threadlocal源码.jpg

    threadlocal源码解析

    Android 中ThreadLocal的深入理解

    Android 中 ThreadLocal 的深入理解 Android 中 ThreadLocal 的深入理解是指在 Android 开发中对 ThreadLocal 的深入理解和应用。ThreadLocal 是 Java 语言中的一种线程内部数据存储机制,通过它可以在指定的线程中...

    Android 详解ThreadLocal及InheritableThreadLocal

    在Android中,ThreadLocal常被用来存储线程相关的数据,例如Handler中的Looper对象,因为Looper与线程紧密关联,每个线程通常只有一个Looper,而ThreadLocal正好满足这种需求。 下面是一个简单的ThreadLocal使用...

    ThreadLocal_ThreadLocal源码分析_

    4. **注意线程池中的ThreadLocal**:线程池中的线程可能会被重用,若不清理ThreadLocal,可能导致后续任务访问到错误的变量副本。 通过理解ThreadLocal的原理和最佳实践,我们可以更有效地利用它来解决多线程环境下...

    ThreadLocal源码分析

    首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象。

    Java并发编程学习之ThreadLocal源码详析

    Java并发编程学习之ThreadLocal源码详析 ThreadLocal是Java并发编程中的一种机制,用于解决多线程访问共享变量的问题。它可以使每个线程对共享变量的访问都是线程安全的,使得多线程编程变得更加简单。 ...

    Android 中 ThreadLocal使用示例

    下面将详细介绍ThreadLocal的工作原理、使用方法以及在Android中的实际应用。 ### 1. ThreadLocal工作原理 ThreadLocal内部实现了一个HashMap,用于存储每个线程与对应的变量副本之间的映射关系。当我们创建一个新...

    ThreadLocal源码以及应用.md

    ThreadLocal源码以及应用

    ThreadLocal源码分析和使用

    ThreadLocal 源码分析和使用 ThreadLocal 是 Java 语言中的一种多线程编程机制,用于解决多线程程序的并发问题。它不是一个 Thread,而是一个 Thread 的局部变量。ThreadLocal 的出现是为了解决多线程程序中的共享...

    ThreadLocal_ThreadLocal源码分析_源码.zip

    ThreadLocal是Java编程语言中的一个类,用于在多线程环境下提供线程局部变量。它为每个线程创建了一个独立的变量副本,每个线程只能访问自己的副本,不会影响其他线程。ThreadLocal的设计思想是解决共享数据在多线程...

    Java中ThreadLocal源码详细注释

    ThreadLocal的作用是提供线程内的局部变量,这种变量在多线程环境下访问时能够保证各个线程里变量的独立性。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是...

    ThreadLocal

    ThreadLocal是Java编程语言中的一个类,用于在多线程环境中提供线程局部变量。它是一种特殊类型的变量,每个线程都有自己的副本,互不影响,从而实现线程间数据隔离。ThreadLocal通常被用来解决线程共享数据时可能...

    Java源码解析ThreadLocal及使用场景

    Java源码解析ThreadLocal及使用场景 ThreadLocal是Java中一个非常重要的类,它在多线程环境下经常使用,用于提供线程本地变量。这些变量使每个线程都有自己的一份拷贝,使得多个线程可以独立地使用变量,不会彼此...

    理解的ThreadLocal类的相关源码(用于博文引用源码下载)

    Java中ThreadLocal工具类(解决多线程程序中并发问题的一种新思路,主要为参数的拷贝问题),感兴趣的话可以查看博文,博文地址:http://blog.csdn.net/otengyue/article/details/38459327

    ThreadLocal源码解析

    ThreadLocal类的作用:为每个线程创建独立的副本,从而保证了线程安全。 ThreadLocal使用代码示例: public class MyThreadLocalTest { private ThreadLocal threadLocal=new ThreadLocal(){ @Override protected...

    java中ThreadLocal详解

    ### Java中ThreadLocal详解 #### 一、ThreadLocal概述 在Java多线程编程中,`ThreadLocal`是一个非常重要的工具类,它提供了一种在每个线程内部存储线程私有实例的方法。通常情况下,当多个线程共享某个变量时,...

    ThreadPoolExecutor源码解析.pdf

    《ThreadPoolExecutor源码解析》 ThreadPoolExecutor是Java并发编程中重要的组件,它是ExecutorService接口的实现,用于管理和调度线程的执行。理解其源码有助于我们更好地控制并发环境下的任务执行,提高系统的...

Global site tag (gtag.js) - Google Analytics