栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

ThreadLocal原理分析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

ThreadLocal原理分析

ThreadLocal类提供线程局部变量,每一个访问这种变量的线程(通过get和set方法),都有独立初始化的变量副本。可以保证存储进去的数据,只被当前线程读取,各线程之间不会相互影响。

 public T get() {
      Thread t = Thread.currentThread();
      ThreadLocalMap map = getMap(t);
      if (map != null) {
          ThreadLocalMap.Entry e = map.getEntry(this);
          if (e != null) {
              @SuppressWarnings("unchecked")
              T result = (T)e.value;
              return result;
          }
      }
      return setInitialValue();
  }
  //getMap方法
  ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
  }
    
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}
static class Entry extends WeakReference> {
     
     Object value;

     Entry(ThreadLocal k, Object v) {
         super(k);
         value = v;
     }
 }

TreadLocal存储在每一个线程的ThreadLocal的ThreadLocalMap里,ThreadLocalMap包含一个Entry数组,并且每个Entry数组存储一个ThreadLocal和其value值。

ThreadLocal提供了get和set方法,set方法向当前线程ThreadLocal.ThreadLocalMap类型的成员变量threadLocals中设置值,key就是ThreadLocal,value就是要设置的值。也就是说,set方法中操作的是ThreadLocal为key,指定值为value,最后将键值对封装成Entry对象放到ThreadLcoal.ThreadLocalMap对象中。

正常情况下,使用线程创建ThreadLocal对象,线程生命周期结束,此时Thread的ThreadLocal对象也会被回收,但是如果使用线程池,有时核心线程会被循环使用,此时有可能会造成内存泄漏

Entry继承了WeakReference,可以知道ThreadLocalMap使用的是ThreadLcoal的弱引用作为key,这样当ThreadLcoal置null后,没有任何强引用指向ThreadLcoal实例,可以顺利被gc回收。否则会造成内存泄漏。但是此时value依然为强引用,所以使用完要用remove方法。
换句话说,在线程池中使用ThreadLocal,ThreadLocalMap中含有多个ThreadLocal–value的Entry,value是强引用,有可能回收不了,需要手动remove

get方法返回当前线程的ThreadLocal变量副本的值。也就是取出每一个Entry对象中,key为ThreadLcoal的对应value值。

demo:

public class Test{
    public static void main(String[] args) {
        ThreadA a1 = new ThreadA();
        a1.setName("thread1");
        a1.start();
        ThreadA a2 = new ThreadA();
        a1.setName("thread2");
        a2.start();
    }

    static class ThreadA extends Thread{
        private static ThreadLocal a = new ThreadLocal<>();
        @Override
        public void run() {
            for(int i=0;i<3;i++){
                a.set(i);
                System.out.println("thread[" +Thread.currentThread().getName()+"]--->" +a.get());
            }
        }
    }
}
thread[thread2]--->0
thread[thread2]--->1
thread[thread2]--->2
thread[Thread-1]--->0
thread[Thread-1]--->1
thread[Thread-1]--->2
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/731545.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号