ThreadLocal 源代码分析(二)

2015-01-27 22:35:49 · 作者: · 浏览: 106
leanup(),根据字面意思它是清理内存的作用,让我们来看源代码:
  /**
         * Cleans up after garbage-collected thread locals.
         */
        private void cleanUp() {
            if (rehash()) {
                // If we rehashed, we needn't clean up (clean up happens as
                // a side effect).
                return;
            }

            if (size == 0) {
                // No live entries == nothing to clean.
                return;
            }

            // Clean log(table.length) entries picking up where we left off
            // last time.
            int index = clean;
            Object[] table = this.table;
            for (int counter = table.length; counter > 0; counter >>= 1,
                    index = next(index)) {
                Object k = table[index];

                if (k == TOMBSTONE || k == null) {
                    continue; // on to next entry
                }

                // The table can only contain null, tombstones and references.
                @SuppressWarnings("unchecked")
                Reference
   
    > reference
                        = (Reference
    
     >) k; if (reference.get() == null) { // This thread local was reclaimed by the garbage collector. table[index] = TOMBSTONE; table[index + 1] = null; tombstones++; size--; } } // Point cursor to next index. clean = index; } 
    
   
从代码可以知道,ThreadLocal 对象被回收了,但是它的弱引用所对应的value却还存在,通过value=null来释放value所占用的内存。并给它设置一个标志用TOMBSTONE。表示这块内存已经被释放了。 这样上面 firstTombstone 这个字段的含义也一目了然了。 到这里我们思考一下,既然使用数组来保存对象,数组肯定要扩容啊,没错,确实有这个方法,叫rehash()
        /**
         * Rehashes the table, expanding or contracting it as necessary.
         * Gets rid of tombstones. Returns true if a rehash occurred.
         * We must rehash every time we fill a null slot; we depend on the
         * presence of null slots to end searches (otherwise, we'll infinitely
         * loop).
         */
        private boolean rehash() {
            if (tombstones + size < maximumLoad) {
                return false;
            }

            int capacity = table.length >> 1;

            // Default to the same capacity. This will create a table of the
            // same size and move over the live entries, analogous to a
            // garbage collection. This should only happen if you churn a
            // bunch of thread local garbage (removing and reinserting
            // the same thread locals over and over will overwrite tombstones
            // and not fill up the table).
            int newCapacity = capacity;

            if (size > (capacity >> 1)) {
                // More than 1/2 filled w/ live entries.
                // Double size.
                newCapacity = capacity * 2;
            }

            Object[] oldTable = this.table;

            // Allocate new table.
            initializeTable(newCapacity);

            // We won't have any tombstones after this.
            this.tombstones = 0;

            // If we have no live entries, we can quit here.
            if (size == 0) {
                return true;
            }

            // Move over entries.
            for (int i = oldTable.length - 2; i >= 0; i -= 2) {
                Object k = oldTable[i];
                if (k == null || k == TOMBSTONE) {
                    // Skip this entry.
                    continue;
                }

                // The table can only contain null, tombstones and references.
                @SuppressWarnings("unchecked")
                Reference
   
    > reference
                        = (Reference
    
     >) k; ThreadLocal
      key = reference.get(); if (key != null) { // Entry is still live. Move it over. add(key, oldTable[i + 1]); } else { // The key was reclaimed. size--; } } return true; } 
    
   
就是当前正在使用的内存大于分配内存的1/2的时候进行数扩容。
还有最后一个方法就是remove了,用来释放内存。
        /**
         * Removes entry for the given ThreadLocal.
         */
        void remove(ThreadLocal
     key) {
            cleanUp();

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

                if (reference == key.reference) {
                    // Success!
                    table[index] = TOMBSTONE;
                    table[index + 1] = null;
                    tombstones++;
                    size--;
                    return;
                }

                if (reference == null) {
                    // No entry found.
                    return;
                }
            }
        }


  通过代码分析也可以知道,也用TOMBSTONE来表示这块内存已经被释放掉了,有兴趣的朋友可以仔细研究代码。
  最后分析下本篇文章最长用到的一个函数:
  
        /**
         * Gets the next index. If we're at the end of the table, we wrap back
         * around to 0.
         */
        private int next(int index) {
            return (index + 2) & mask;
        }


这方法的好处是可以循环遍历,嗯 ,以后借鉴这种方法也是不错的。 

本人最后提醒一下:1 使用ThreadLocal 要真正实行线程之间数据无干扰的话,必须要进行对象深拷贝。 2 使用Thr