前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >threadlocal记录

threadlocal记录

原创
作者头像
猎户星座1
修改2020-09-23 10:16:07
6030
修改2020-09-23 10:16:07
举报
文章被收录于专栏:Java Study
代码语言:javascript
复制
记录一下 threadlocal  发现再不记录的话就要忘掉了



首先threadlocal 在哪里吧

 thread 里
    ThreadLocal.ThreadLocalMap threadLocals = null;

但如果你直接从 thread 里能得到吗
并不能   Thread.currentThread().得不到

只记录 threadlocal的知识的话其实并没有什么意义吧感觉   结合应用场景去让自己理解threadlocal
网上说的threadlocal 的用途 :说可以用在 数据库 的线程池中  起到隔离 每个线程链接不一样的作用
或者 http 中的 session  也是,当时我对session 也很有疑惑,session 是服务端的技术,然后的话,
我当时就在想为什么 比如我这个用户往session 里放数据对吧,然后前端可以取到。
那我只要一个用户向session 存放了数据,别的用户 就完全可以${session.value} 完全可以取到这个值啊,
那这完全不隔离啊,是不是因为这个原因,才有了model 或者 modelanview 这样的返回结果,存放的数据只对下一次有效。
但后来,网上的教程说,因为网上threadlocal 的讲知识的教程实在太多了,

在我看的 3y 大哥中的,
https://www.juejin.im/post/6844903586984361992   避免一些参数的传递的理解可以参考一下Cookie和Session
然后在想,cookie  session 会话,是不是利用了 threadlocal 这个技术
实现的,因此所以就是说,我们的seesion 是不会被别人所访问的。因为tomcat 分配给每个用户的工作线程是不一样的,
后来想你的一次http 请求完成后 就失效了对吧, 但session 还是有的。
其实 之前就学过 session 和 cookie 都是根据 id 来确定要给哪个浏览器 传数据的,你的浏览器会话是一个id,再看一个网页就是另一个会话了
 和 threadlocal 没有关系。


除了上面两个实际的东西,因为自己学过日志这块,会了解到mdc  mdc 也是一个 InheritableThreadLocal 它是可以从父线程中继承value 的threadlocal
其实也是用到 threadlocal 这种思想。

还有被大家广泛写的 threadlocal 的内存泄漏问题,其实和弱引用没有什么关系,如果key 是强引用更会出现问题,如果是强引用的话,
这句话括号是 别人写的

{
key 使用强引用:引用的ThreadLocal的对象被回收了,但是ThreadLocalMap还持有ThreadLocal的强引用,如果没有手动删除,ThreadLocal不会被回收,导致Entry内存泄漏。

key 使用弱引用:引用的ThreadLocal的对象被回收了,由于ThreadLocalMap持有ThreadLocal的弱引用,即使没有手动删除,ThreadLocal也会被回收。value在下一次ThreadLocalMap调用set,get,remove的时候会被清除。

官方文档的说法:

To help deal with very large and long-lived usages, the hash table entries use WeakReferences for keys.
为了处理非常大和生命周期非常长的线程,哈希表使用弱引用作为 key。
建议:
每次使用完ThreadLocal,都调用它的remove()方法,清除数据。
文章出处 现在在审核:
https://www.jianshu.com/p/a1cd61fa22da(原文)    https://www.cnblogs.com/myseries/p/12081507.html
}


所以官方 就是考虑到了 threadlocal 和 threadlocalmap 与thread 的这种关系,才使用弱引用的。 而且官方想到了这个问题,就是在每次你
get set  remove 的时候都会监测 key 是否为null 的 null 的话也将value 为null 去让value 被回收掉,所以这个问题多了解才知道。

学到现在的话,感觉对threadlocal 这种,对在一次http 请求内不同程序之间的存值和取值是相当有用的感觉,取到的都是这次请求内的,这也让我联想到
mdc 一次日志请求 打印的时间很短,所以很适合使用 threadlocal 记录。

因为自己用到的threadlocal 挺多的,各种日志实现的mdc 也是不一样的 logback 就是使用了threadlocal 而log4j 还是使用的 InheritableThreadLocal
然后看同事的自己写的 threadlocal 怎么去实现的, 还要promagent 这个框架的话也是使用到了 threadlocal 。


看一个 threadlocal 的 get操作
首先 得到当前线程  getMap  就是得到从当前线程中  ThreadLocalMap

 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();
 }


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


这个 threadlocalMap 是一个 threadlocal 的静态内部类
map 是靠 entry 来实现的,

 static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

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



 private Entry[] table;

  ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
 }

实际看到 也是用一个 数组来实现的, 拉不拉链的话不很确定,但是估计一个线程存放的东西不像hashmap 的多。
而且 threadlocal 是一个线程内部的map 也不存在线程安全问题。

https://www.juejin.im/post/6844903586984361992

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档