ThreadLocal初探

该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。(很绕口!!)

我的理解:它本身能够被多个线程共享使用,ThreadLocal类提供了get(),set()方法,在不同的线程中调用它的set方法进行设值(可以简单理解值是保存在一个map中),不会相互影响,因为每个线程拥有独立的"map",值是保存在自己的"map"中的。每个线程都只能获取到自己的"map",因此只有自己才可以通过get来获取设置的值。通过这种方式很好的隔离了多线程执行时对局部变量的操作。

ThreadLocal的几个方法

set(T value) //将此线程局部变量的当前线程副本中的值设置为指定值。

initialValue() //返回此线程局部变量的当前线程的“初始值”。

remove()  //移除此线程局部变量当前线程的值。

get() //返回此线程局部变量的当前线程副本中的值。

首先来分析它的set方法源码,当我们需要设值时就需要调用该方法

public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

在set方法中首先获取当前正在执行的线程对象,然后获取到ThreadLocalMap对象,可以简单的将他理解为一个map,如果map不为空就将value值保存到map中,其中键是当前的ThreadLocal对象,如果map为空就创建一个并将value保存在其中。前面说过,每一个线程都用于自己的map,进入getMap()可以发现,就是通过当前线程来获取的。

/**
     * @param  t the current thread
     * @return the map
     */
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

如果map为空就会执行createMap(t,value)来创建一个map并将value保存进去。

/**
     * @param t the current thread
     * @param firstValue value for the initial entry of the map
     */
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);//1
    }

注释//1创建了一个map并保存value,最后将该map赋给当前线程的threadLocals成员变量,下次获取map直接返回这个成员变量的值就好。

当我们需要取值的时候就需要调用它的get()方法,源码如下:

/**
     * @return the current thread's value of this thread-local
     */
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);//1
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

//1处通过当前线程获取map,获取的map其实就是当前正在执行线程的成员变量,获取到map后如果map不为空就通过map来获取值,获取到值就将它返回。如果获取不到值或者map为空就返回一个默认的初始值,初始值一般为null。setInitialValue()源码如下:

/**
     * @return the initial value
     */
    private T setInitialValue() {
        T value = initialValue();//1
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

很简单,在//1处会直接返回null,这个值就是初始值,然后获取当前正在执行的线程,通过线程来获取自己的map,如果map不为空就将初始值保存进去,为空则创建一个map再将初始值保存进去。

需要注意,一般如果在一个线程中没有调用set方法设值,直接调用get方法,返回的是默认的初始值,如果之前调用了set方法,再调用get方法返回的就是我们设置的值。如果我们希望返回一个我们期望的初始值,可以继承ThreadLocal类来重写它的initialValue()方法。如下

	static ThreadLocal tl=new ThreadLocal() {
		@Override
		protected Object initialValue() {
			// TODO Auto-generated method stub
			return "hello!";
		}
	};

这时如果我们在没有调用set的情况下调用get方法就会返回"hello!"而不会再是null。

最后来看看remove()方法:

/**
     * Removes the current thread's value for this thread-local variable.  
     * @since 1.5
     */
     public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

很简单,直接移除当前线程map中保存的值。

最后需要注意ThreadLocalMap是ThreadLocal内部的静态类。是通过它来保存和获取值的,而ThreadLocal给我的感觉更像是一个工具类,封装了对ThreadLocalMap的一些操纵。



猜你喜欢

转载自blog.csdn.net/start_mao/article/details/80006220