ThreadLocal的理解与使用

首先来看一下多线程问题:

class Test{
    private static Integer data = 0;//使用Integer普通变量保存数据
    public static void set(Integer num){
        data = num;
    }
    public static Integer get(){
        System.out.println("num ==> " +data);
        return data;
    }
}

public class CopyOfMainTest{
    public static void main(String[] args){
        for(int i=0;i<10;i++){
            final int num = i;
            new Thread(){
                public void run(){
                    Test.set(num);
                    Test.get();
                }
            }.start();
        }
    }
}

执行的结果如下:

num ==> 4
num ==> 0
num ==> 4
num ==> 4
num ==> 3
num ==> 5
num ==> 7
num ==> 9
num ==> 9
num ==> 8

分析:可以看到以下多个线程中data的值时一样的,使得数据结果很混乱,按照正常的思维模式,每一个线程应该得到一个数据,从0到9,这就是我们经常说的线程安全问题,这里肯定是不安全的。当然了你可以用synchronized去解决这个问题,但是多线程的并发处理的效率就会大大折扣。


来看一个用ThreadLocal存放变量的例子:

//使用ThreadLocal保存数据
class Test{
    public static ThreadLocal<Integer> local = new ThreadLocal<Integer>();
    public static void set(Integer num){
        local.set(num);
    }
    public static Integer get(){
        System.out.println("num ==> " + local.get());
       return local.get();
    }
}

public class CopyOfMainTest{
    public static void main(String[] args){
        for(int i=0;i<10;i++){
            final int num = i;
            new Thread(){
                public void run(){
                    Test.set(num);
                    Test.get();
                }
            }.start();
        }
    }
}


执行的结果如下:

num ==> 0
num ==> 1
num ==> 2
num ==> 3
num ==> 6
num ==> 5
num ==> 8
num ==> 4
num ==> 9
num ==> 7

只是顺序上变了而已,每个线程都得到自己应该得到的Integer变量值。


分析原因:

通过对java API的查阅,发现Tread 和ThreadLocal都在java.lang包下。在java.lang.Thread源码中,有这样一段代码。这个threadLocals就是那些设计者们已经为我们考虑了在线程中存放变量的问题。

    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;
在看ThreadLocal源码:

 /**
     * 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() {//get方法
        Thread t = Thread.currentThread();//获取当前上下文线程(哪个线程在调用该方法)
        ThreadLocalMap map = getMap(t);//把当前线程作为参数丢给getMap方法,返回一个ThreadLocal的内置对象ThreadLocalMap (map)
        if (map != null) {
              ThreadLocalMap.Entry e = map.getEntry(this);//取出当前上下ThreadLocal对象对应的值 Entry getEntry(ThreadLocal key) if (e != null) return (T)e.value; } return setInitialValue();
       }

/**
     * Sets the current thread's copy of this thread-local variable
     * to the specified value.  Most subclasses will have no need to
     * override this method, relying solely on the {@link #initialValue}
     * method to set the values of thread-locals.
     *
     * @param value the value to be stored in the current thread's copy of
     *        this thread-local.
     */
    public void set(T value) {//set方法
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);//把当前的ThreadLocal对象作为key把值存入,set(ThreadLocal key, Object value)
        else
            createMap(t, value);
    }

/**
     * Get the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param  t the current thread
     * @return the map
     */
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    } 
 

通过对源码的分析发现,ThreadLocal在存变量的时候是根据当前上下文线程 和 当前ThreadLocal对象存入数值的。所以当调用get方法时,根据当前上下文线程和ThreadLocal对象就取出了自己唯一的那个值,而不会取到别的线程的值。


在实际开发中,在拦截器中判断当前用户登录成功以后,可以用ThreadLocal来存放用户信息。


强烈推荐两篇文章:

http://qiankunli.github.io/2014/09/02/ThreadLocal.html

http://woshixy.blog.51cto.com/5637578/1275284


注册没几天,就写了一篇,写的不好,请大家提出意见,慢慢改进。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值