并发基础5(ThreadLacal)

目录

1:ThreadLocal是什么

2:ThreadLocal用法

2.1:代码实例

2.2:源码分析

3:ThreadLocal知识点


1:ThreadLocal是什么

ThreadLocal是Thread类的一个成员变量,每次创建一个线程,就会有属于这个线程自己的成员变量ThreadLocal,不同的线程不会相互干扰。在多线程的环境下get、set都是隔离的,保证了线程安全。在线程的生命周期内可以减少方法之间的参数传递,使用ThreadLocal来从传递参数减少复杂度。

2:ThreadLocal用法

2.1:代码实例:

​
public class Test {
    //类变量
    private static  ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) {
    Thread thread1=  new Thread(new Runnable() {
            @Override
            public void run() {
                Test.threadLocal.set("thread1变量");
                remove("thread1");
                System.out.println("thread1获取当前线程的:"+threadLocal.get());
            }
        },"线程1");


        Thread thread2=   new Thread(new Runnable() {
            @Override
            public void run() {
                Test.threadLocal.set("thread2变量");
                remove("thread2");
                System.out.println("thread2获取当前线程的:"+threadLocal.get());


            }
        },"线程2");

        thread1.start();
        thread2.start();


    }


    public static void remove(String s) {
        //打印当前线程中本地内存中本地变量的值
        System.out.println(s + " :" + threadLocal.get());
        //清除本地内存中的本地变量
        threadLocal.remove();
    }
}

​

输出结果:

2.2:源码分析

ThreadLocal的set()方法:

ThreadLocal的set()方法实际上就是往ThreadLocalMap设置值,key是ThreadLocal对象弱引用,值Value是传递进来的对象

我们得知,当我们在线程中使用Threadloacl并且set值的时候,这是一个线程的成员变量,线程独有。

可看出ThreadLocalMap是ThreadLocal的内部静态类,而它的构成主要是用Entry来保存数据 ,而且还是继承的弱引用。在Entry内部使用ThreadLocal作为key,使用我们设置的value作为value。详细内容要大家自己去跟。

//Thread类的成员变量,ThreadLocal类的内部类ThreadLocalMap
    ThreadLocal.ThreadLocalMap threadLocals = null;

//ThreadLocal的set方法
 public void set(T value) {
        Thread t = Thread.currentThread();//获取线程
        //获取线程中的属性 threadLocalMap ,如果threadLocalMap 不为空,
        //则直接更新要保存的变量值,否则创建threadLocalMap,并赋值
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            map.set(this, value);
        } else {
            //创建ThreadLocalMap,并且赋值
            createMap(t, value);
        }
    }

//创建ThreadLocalMap,接受参数是当前线程和传递的值
 void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

    //ThreadLocalMap构造器
  ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            //默认16个Entity数组
            table = new Entry[INITIAL_CAPACITY];
            //hash取模,存放在对应的位置
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            //key是threallocal entity是实现弱引用
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }

//查看Entry 是继承了弱引用
 static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;
            //entity构造器
            Entry(ThreadLocal<?> k, Object v) {
                super(k);//key的构造函数是一个弱引用的ReferenceQueue
                value = v;
            }
        }

ThreadLocal的get方法:

有源码可知就是获取当前线程的ThreadLocal的ThreadLocalMap中的entity

 public T get() {
        //1、获取当前线程
        Thread t = Thread.currentThread();
        //2:根据当前线程,获取对应的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            //3:获取threalLocalMap中存储的值
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        //如果ThreadLocalMap是null,初始化创建一个ThreadLocalMap
        return setInitialValue();
    }

 ThreadLocal的remove方法:

为什么移除了key还要删除呢?实际上 ThreadLocalMap 中使用的 key 为 ThreadLocal 的弱引用,弱引用的特点是,如果这个对象只存在弱引用,那么在下一次垃圾回收的时候必然会被清理掉。

public void remove() {
        //根据当前线程获取当前线程的ThreadLocalMap
         ThreadLocalMap m = getMap(Thread.currentThread());
        //移除threadlocal
         if (m != null) {
             m.remove(this);
         }
     }


 /**
         * Remove the entry for key.
         */
        private void remove(ThreadLocal<?> key) {
            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                //移除key成功
                if (e.refersTo(key)) {
                    //把Entity删除,为什么呢?
                    e.clear();
                    expungeStaleEntry(i);
                    return;
                }
            }
        }

3:ThreadLocal知识点

1:属于每一个线程Thread的私有变量,线程独有安全,可以在线程中传递参数

2:set之后必须调用remove方法,因为ThreadLocal的ThreadLocalMap是Entity,Entity的key是ThreadLocal的弱引用,所以如果 ThreadLocal 没有被外部强引用的情况下,在垃圾回收的时候会被清理掉的,这样一来 ThreadLocalMap中使用这个 ThreadLocal 的 key 也会被清理掉。但是,value 是强引用,不会被清理,这样一来就会出现 key 为 null 的 value。

阿里二面:ThreadLocal内存泄露灵魂四问,人麻了!-腾讯云开发者社区-腾讯云

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值