ThreadLocal理解

1.ThreadLocal用处:

当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本,从而达到线程安全。


例如:

public class TestNum {
    // ①通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值
    private ThreadLocal seqNum = new ThreadLocal(){
        @Override
        protected User initialValue() {
            return new User();
        }
    };
}

变量seqNum使用ThreadLocal维护的一个User变量


2.案例详解与分析

当使用:

TestNum sn = new TestNum();
        // ③ 3个线程共享sn,各自产生序列号
        TestClient t1 = new TestClient(sn);
        TestClient t2 = new TestClient(sn);
        TestClient t3 = new TestClient(sn);
        t1.start();
        t2.start();
        t3.start();

在每一个线程中,都会创建一个User对象,保存在Thread.threadLocals变量保存, Thread. threadLocals变量是一个key-value型的变量,key是当前维护user对象的threadLocal,


1》 怎么创建User:

ThreadLocal源码:

初始化:initialValue(): return newUser();

 /**
     * Returns the current thread's "initial value" for this
     * thread-local variable.  This method will be invoked the first
     * time a thread accesses the variable with the {@link #get}
     * method, unless the thread previously invoked the {@link #set}
     * method, in which case the initialValue method will not
     * be invoked for the thread.  Normally, this method is invoked at
     * most once per thread, but it may be invoked again in case of
     * subsequent invocations of {@link #remove} followed by {@link #get}.
     *
     * 

This implementation simply returns null; if the * programmer desires thread-local variables to have an initial * value other than null, ThreadLocal must be * subclassed, and this method overridden. Typically, an * anonymous inner class will be used. * * @return the initial value for this thread-local */ protected T initialValue() { return null; }


为每个thread创建User对象:

 /**
     * 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 map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }

    /**
     * Variant of set() to establish initialValue. Used instead
     * of set() in case user has overridden the set() method.
     *
     * @return the initial value
     */
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

在获取User对象时,会根据当前线程,获取线程的thread.threadLocals,如果当前线程之前没有存储过这个user,就创建调用setInitialValue(),如果有就返回:

 

ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;


2》关于ThreadLocalmap:

a.ThreadLocal的内部类;

b.key-value类型存储;

c.key是当前ThreadLocal对象,value就是当前threadLocal维护的对象user

d.每个线程都有一个threadLocals,用于维护这个线程的线程安全的一系列对象

e.ThreadLocal中定义的子类,但是在Thread类中存在变量


3》销毁user:

由于ThreadLocal维护的user对象是跟当前线程相关的,只保存在当前线程的threadLocals变量中,thread会在exit()方法中将threadLocal变量至空。


    /**
     * This method is called by the system to give a Thread
     * a chance to clean up before it actually exits.
     */
    private void exit() {
        if (group != null) {
            group.threadTerminated(this);
            group = null;
        }
        /* Aggressively null out all reference fields: see bug 4006245 */
        target = null;
        /* Speed the release of some of these resources */
        threadLocals = null;
        inheritableThreadLocals = null;
        inheritedAccessControlContext = null;
        blocker = null;
        uncaughtExceptionHandler = null;
    }


3.与synchronized对比:

1》都是解决线程同步问题


2》synchronized修饰:线程将排队访问变量,以时间换空间;threadloca修饰:会为每个线程创建一个副本,以空间换时间


3》synchronized修饰:每个线程的调用后对变量的修改都是有影响的;threadloca修饰:线程之间对变量的修改互不影响,各自持有变量的副本


4.关于Looper:

1》Looper类中有静态变量:

    static final ThreadLocal sThreadLocal = new ThreadLocal();

sThreadLocal是静态的,所以每个Thread.threadLocals中对应的key是不变的,所以每个thread中,Looper只能有一个。这样就“ 保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue”






你可能感兴趣的:(学习笔记,理論知識)