java线程本地变量ThreadLocal详解

  

<强>介绍
  

  

ThreadLocal作为JDK1.2以来的一个java。朗包下的一个类,在面试和工程中都非常重要,这个类的主要目的是提供线程本地的变量,所以也有很多地方把这个类叫做线程本地变量
  

  

从字面理解,这个类为每个线程都创建了一个本地变量,实际上是ThreadLocal为变量在每个线程中都创建了一个副本,使得每个线程都可以访问自己内部的副本变量
  

  

通常提到多线程,都会考虑变量同步的问题,但是ThreadLocal并不是为了解决多线程共享变量同步的问题,而是为了让每个线程的变量不互相影响,相当于线程之间操纵的都是变量的副本,自然就不用考虑多线程竞争的问题,也自然没有性能损耗
  

  

<强>使用方式
  

  

先来看常用的这几个方法
  

        公共T get () {}   公共空集(T值){}   公共空间remove () {}   保护T initialValue () {}
     

显而易见,get()方法获取线程拥有的副本值,设置()方法进行设值,删除()方法移除,initialValue()进行变量初始化,我们先来看下面这个实例,同时体会一下应用场景
  

        公开课演示{   公共静态ThreadLocalthreadLocal=零;   公共静态void main (String [] args) {   threadLocal=new ThreadLocal () {/* *   *通过重写该方法来初始化ThreadLocal的值   */@Override   保护整数initialValue () {   返回10;   }   };   MyThread t1=new MyThread (20);   MyThread t2=new MyThread (30);   t1.start ();//这里为了描述清晰,省略了try - catch语句块   t1.join ();   t2.start ();   }   }      

在上述方法中,我们定义并初始化一个ThreadLocal类为10(通过重写initialValue()方法实现),然后开启了两个线程,同时我们这里让t2线程等待t1线程执行完再执行
  

  

MyThread类详细信息如下
  

        类MyThread扩展线程{   私人int val=0;   MyThread (int val) {   这一点。val=val;   }   @Override   公共空间run () {   System.out.println (Thread.currentThread() +”然后就——“+ Demo.threadLocal.get ());   Demo.threadLocal.set (val);   System.out.println (Thread.currentThread () +”————“+ Demo.threadLocal.get ());   }   }      

我们通过调用ThreadLocal对象的获得()方法来获取当前的值,然后通过设置()方法设置一个新值(每个线程我们设置不同的值),然后再通过得到()方法来获取设置后的值
  

  

运行结果如下

  

癹ava线程本地变量ThreadLocal详解"

  

重点是图中标注的t2线程变量的初始值,虽然我们在t1线程中修改了变量的值,但是在t2线程中变量值并没有被改变,这样就实现了每个线程独有的变量
  

  

同时,如果一个ThreadLocal对象要在很多地方进行复用时,需要在使用前通过调用* *删除()* *方法来将本地变量恢复到默认值
  

  

也许有人会问了,我们给每个线程定义自己的私有变量不是也可以实现同样的操作吗,理论上当然是可行的,但是ThreadLocal远比私有变量的形式方便,不仅可以在线程外部进行统一的初始化,而且避免在线程内部额外设置变量
  

  

<强>原理
  

  

点进ThreadLocal的源码中,发现并没有存储变量的字段值,那看来ThreadLocal并不负责保存变量,我们只能从方法下手
  

  

先看初始()方法,毕竟我们的变量默认初始值就是在这个方法中设置,如下

        保护T initialValue () {   返回null;   }      

我们在每次创建ThreadLocal都要重写这个方法,那么这个方法到底在哪调用呢,我们点进得到()方法源码中,如下
  

        公共T get () {//获取当前线程   线程t=Thread.currentThread ();//获取当前线程的地图   ThreadLocalMap地图=getMap (t);   如果(地图!=null) {   ThreadLocalMap。输入e=map.getEntry(这个);   如果(e !=null) {=(T) e.value T结果;   返回结果;   }   }//如果地图为空则进行创建   返回setInitialValue ();   }      

有点眉头了,我们发现这里获取了一个ThreadLocalMap对象,所以会想到有可能是通过让线程与变量作一个千伏表,来实现每个线程拥有自己独有的变量

java线程本地变量ThreadLocal详解