Android ThreadLocal 机制

在看Android Handler 时遇到了ThreadLocal这个东东,不知到它是干什么的,上网查了查,理解如下:


在 Android 中ThreadLocal并不是存储Thread或者标记Thread所用,它的作用就是:

在不同线程中,修改变量时只是修改了该变量在该线程的副本,而对其他线程不影响。(就是在不同的线程中变量有不同的副本)

这与synchronized机制正好相反,synchronized是防止不同线程对相同资源的竞争。 (就是在同一时间只能有一个进程访问)


下面对ThreadLocal的部分源码进行概要说明:(有好多地方都没看懂.......)

这是Android2.3.3中的源码和java的源码有点小区别,不过不影响整体功能

public class ThreadLocal<T> {


    /**
     *获取当前线程的变量的值,如果不存在entry(指的就是ThreadLocal.localValues)就新建一个
     * 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);
    }


    /**这个方法是一个延迟调用方法,在第一次调用get()方法是调用,我们可以在实现ThreadLocal时覆盖它而实现不同线程中变量有不同的副本
     *其实在ThreadLocal的localValues中保存的就是这个方法传过来的值的引用
     * 如果在initialValue这儿没有覆盖的话,ThreadLocal中Value保存的就是get传过来的值的引用
     *
     * Provides the initial value of this variable for the current thread.
     * The default implementation returns {@code null}.
     *
     * @return the initial value of the variable.
     */
    protected T initialValue() {
        return null;
    }


    /**为当前线程的变量赋值
     * 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);
    }


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


	
    /**存储以Hash的方式存储不同线程的变量
     * Per-thread map of ThreadLocal instances to values.
     */
    static class Values {
        /**为线程添加变量
         * 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;
                }
            }
        }
	/**在第一次没有为该线程找到变量是,为其赋值
         * Gets value for given ThreadLocal after not finding it in the first
         * slot.
         */
        Object getAfterMiss(ThreadLocal<?> key) {
            Object[] table = this.table;
            int index = key.hash & mask;


            // If the first slot is empty, the search is over.
            if (table[index] == null) {
                Object value = key.initialValue();


                // If the table is still the same and the slot is still empty...
                if (this.table == table && table[index] == null) {
                    table[index] = key.reference;
                    table[index + 1] = value;
                    size++;


                    cleanUp();
                    return value;
                }


                // The table changed during initialValue().
                put(key, value);
                return value;
            }


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


            // Continue search.
            for (index = next(index);; index = next(index)) {
                Object reference = table[index];
                if (reference == key.reference) {
                    return table[index + 1];
                }


                // If no entry was found...
                if (reference == null) {
                    Object value = key.initialValue();


                    // If the table is still the same...
                    if (this.table == table) {
                        // If we passed a tombstone and that slot still
                        // contains a tombstone...
                        if (firstTombstone > -1
                                && table[firstTombstone] == TOMBSTONE) {
                            table[firstTombstone] = key.reference;
                            table[firstTombstone + 1] = value;
                            tombstones--;
                            size++;


                            // No need to clean up here. We aren't filling
                            // in a null slot.
                            return value;
                        }


                        // If this slot is still empty...
                        if (table[index] == null) {
                            table[index] = key.reference;
                            table[index + 1] = value;
                            size++;


                            cleanUp();
                            return value;
                        }
                    }


                    // The table changed during initialValue().
                    put(key, value);
                    return value;
                }


                if (firstTombstone == -1 && reference == TOMBSTONE) {
                    // Keep track of this tombstone so we can overwrite it.
                    firstTombstone = index;
                }
            }
        }

    }
......................
}


写了点代码验证ThreadLocal的功能如下:

import java.lang.Thread;
import java.util.Random;
import java.lang.ThreadLocal;
class Student {
    private int age = 0;
    public void setAge (int a) {
        this.age = a;
        return;
    }
    public int getAge () {
        return this.age;
    }
    public Student(){}
    public Student(int a) {
        this.age = a;
    }
}

public class TestThreadLocal implements Runnable {
    Student student = new Student();
    ThreadLocal<Student> threadLocal = new ThreadLocal<Student>() {
        @Override
        protected Student initialValue() {//重写initialValue,实现在获取变量的拷贝而不是源变量
            System.out.println("initialValue of student");
            return new Student(888);
        }
    };

    public static void main(String[] args) {
        TestThreadLocal ts = new TestThreadLocal();
        Thread t1 = new Thread(ts,"t1");
        Thread t2 = new Thread(ts,"t2");
        t1.start();
        t2.start();
    } 

    public void run() {
        String currentThreadName = Thread.currentThread().getName();
        System.out.println("CurrentThread is:"+currentThreadName);
        Random random = new Random();
        int age = random.nextInt(100);
        System.out.println("thread "+currentThreadName+" set age to "+age);//当前线程Student.age
        Student tstudent = threadLocal.get();//获取当前线程的变量
        if(tstudent == this.student) {
            System.out.println("there is no copy...................");
        }
        tstudent.setAge(age);//改变年龄
        System.out.println("thread " + currentThreadName + " set age to " + tstudent.getAge());//当前线程Student.age

        System.out.println("main thread student age is " + student.getAge());//主线程中student.age
        try {
            Thread.sleep(500);
        } catch(Exception e) {
        
        }
    }
}


运行结果如下:

CurrentThread is:t2
CurrentThread is:t1
thread t2 set age to 40
thread t1 set age to 82
initialValue of student
initialValue of student
thread t2 set age to 40
thread t1 set age to 82
main thread student age is 0
main thread student age is 0

参考资料:

http://lavasoft.blog.51cto.com/62575/51926

http://www.blogjava.net/pengpenglin/archive/2008/09/05/227276.html

http://zhxing.iteye.com/blog/611324

非常感谢


又学习了一种多线程编程思想,o(∩∩)o...哈哈

但是关于变量用HashMap存储那块没怎么看懂,以后有时间在好好看看。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值