您当前的位置: 首页 > 

庄小焱

暂无认证

  • 2浏览

    0关注

    805博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

JDK源码——ThreadLocal类

庄小焱 发布时间:2021-03-31 20:26:24 ,浏览量:2

摘要

ThreadLocal,简单翻译过来就是本地线程,但是直接这么翻译很难理解ThreadLocal的作用,如果换一种说法,可以称为线程本地存储。简单来说,就是ThreadLocal为共享变量在每个线程中都创建一个副本,每个线程可以访问自己内部的副本变量。这样做的好处是可以保证共享变量在多线程环境下访问的线程安全性。

一、ThreadLocal的使用

通过一个简单的例子来演示一下ThreadLocal的作用,这段代码是定义了一个静态的成员变量num,然后通过构造5个线程对这个num做递增。

public class ThreadLocalDemo {

    private static Integer num=0;

    public static void main(String[] args) {
        Thread[] threads=new Thread[5];
        for(int i=0;i{
               num+=5;
               System.out.println(Thread.currentThread().getName()+" : "+num);
            },"Thread-"+i);
        }

        for(Thread thread:threads){
            thread.start();
        }
    }
}
----------------------------------------------------------
运行结果

Thread-0 : 5
Thread-1 : 10
Thread-2 : 15
Thread-3 : 20
Thread-4 : 25

每个线程都会对这个成员变量做递增,如果线程的执行顺序不确定,那么意味着每个线程获得的结果也是不一样的。

public class ThreadLocalDemo {

    private static final ThreadLocal local=new ThreadLocal(){
        protected Integer initialValue(){
            return 0; //通过initialValue方法设置默认值
        }
    };

    public static void main(String[] args) {
        Thread[] threads=new Thread[5];
        for(int i=0;i{
                int num=local.get().intValue();
                num+=5;
               System.out.println(Thread.currentThread().getName()+" : "+num);
            },"Thread-"+i);
        }

        for(Thread thread:threads){
            thread.start();
        }
    }
}
-------------------------------------------------------------
运行结果

Thread-0 : 5
Thread-4 : 5
Thread-2 : 5
Thread-1 : 5
Thread-3 : 5

从结果可以看到,每个线程的值都是5,意味着各个线程之间都是独立的变量副本,彼此不相互影响。ThreadLocal会给定一个初始值,也就是initialValue()方法,而每个线程都会从ThreadLocal中获得这个初始化的值的副本,这样可以使得每个线程都拥有一个副本拷贝。

二、ThreadLocal的方法 2.1 set方法的实现

set方法是设置一个线程的局部变量的值,相当于当前线程通过set设置的局部变量的值,只对当前线程可见。

    public void set(T value) {
        Thread t = Thread.currentThread();//获取当前执行的线程
        ThreadLocalMap map = getMap(t); //获得当前线程的ThreadLocalMap实例
        if (map != null)//如果map不为空,说明当前线程已经有了一个ThreadLocalMap实例
            map.set(this, value);//直接将当前value设置到ThreadLocalMap中
        else
            createMap(t, value); //说明当前线程是第一次使用线程本地变量,构造map
    }
  • Thread.currentThread 获取当前执行的线程
  • getMap(t) ,根据当前线程得到当前线程的ThreadLocalMap对象,这个对象具体是做什么的?稍后分析
  • 如果map不为空,说明当前线程已经构造过ThreadLocalMap,直接将值存储到map中
  • 如果map为空,说明是第一次使用,调用createMap构造
2.1.1 ThreadLocalMap

ThreadLocalMap map=getMap(t)获得一个ThreadLocalMap对象,那这个对象是干嘛的呢?其实不用分析,基本上也能猜测出来,Map是一个集合,集合用来存储数据,那么在ThreadLocal中,应该就是用来存储线程的局部变量的。ThreadLocalMap这个类很关键。

    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

t.threadLocals实际上就是访问Thread类中的ThreadLocalMap这个成员变量:

public
class Thread implements Runnable {
 /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;
...
}

从上面的代码发现每一个线程都有自己单独的ThreadLocalMap实例,而对应这个线程的所有本地变量都会保存到这个map内。

ThreadLocalMap是在哪里构造? 在set方法中,有一行代码createmap(t,value);,这个方法就是用来构造ThreadLocalMap,从传入的参数来看,它的实现逻辑基本也能猜出出几分吧。

    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

Thread t 是通过Thread.currentThread()来获取的表示当前线程,然后直接通过new ThreadLocalMap将当前线程中的threadLocals做了初始化 ThreadLocalMap是一个静态内部类,内部定义了一个Entry对象用来真正存储数据。

static class ThreadLocalMap {
        static class Entry extends WeakReference            
关注
打赏
1657692713
查看更多评论
0.0399s