您当前的位置: 首页 > 

zmc@

暂无认证

  • 2浏览

    0关注

    142博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

ThreadLocal和ThreadLocalMap

zmc@ 发布时间:2020-06-01 11:37:19 ,浏览量:2

 

1.ThreadLocal是什么?

是用来存放我们需要能够线程隔离的变量的,那就是线程本地变量。也就是说,当我们把变量保存在ThreadLocal当中时,就能够实现这个变量的线程隔离了。

 

 

entry中的key使用了弱引用:

static class ThreadLocalMap {

        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
        static class Entry extends WeakReference k = e.get();
                if (k == null) {
                    e.value = null;
                    tab[i] = null;
                    size--;
                } else {
                    int h = k.threadLocalHashCode & (len - 1);
                    if (h != i) {
                        tab[i] = null;

                        // Unlike Knuth 6.4 Algorithm R, we must scan until
                        // null because multiple entries could have been stale.
                        while (tab[h] != null)
                            h = nextIndex(h, len);
                        tab[h] = e;
                    }
                }
            }
            return i;
        }

该方法的作用:

擦除某个下标的Entry(置为null,可以回收),同时检测整个Entry[]表中对key为null的Entry一并擦除,重新调整索引。

该方法,在每次调用ThreadLocal的get、set、remove方法时都会执行,即ThreadLocal内部已经帮我们做了对key为null的Entry的清理工作。

但是该工作是有触发条件的,需要调用相应方法,假如我们使用完之后不做任何处理是不会触发的。

 

 

 

 

知乎上看到一张图画的很清晰:ThreadLocal其实只是个符号意义,本身不存储变量,仅仅是用来索引各个线程中的变量副本

 

 

3.Spring如何保证bean在多线程环境下的安全?

1.为什么会有线程安全问题?

例如Spring的jdbc的connection,如果在一次请求中多次操作同一个数据库表,然后从线程池(连接池)中获取connection,每次都有可能拿到不同的connection,这样就没有办法保证事务-----》因为不同的connection,直接变成了分布式事务

从而产生一系列问题

 

2.如何解决?

首先,肯定Spring的单例缓存池使用的是concurrentHashmap,保证写入容器的线程安全

然后,使用threadLocal,用来解决从池中获取connection随机问题以及多线程资源竞争问题

 

 

4.threadLocal总结?

  • (强制)在代码逻辑中使用完ThreadLocal,都要调用remove方法,及时清理。

目前我们使用多线程都是通过线程池管理的,对于核心线程数之内的线程都是长期驻留池内的。显式调用remove,一方面是防止内存泄漏,最为重要的是,不及时清除有可能导致严重的业务逻辑问题,产生线上故障(使用了上次未清除的值)。

最佳实践:在ThreadLocal使用前后都调用remove清理,同时对异常情况也要在finally中清理。

  • (非规范)对ThreadLocal是否使用全局static修饰的讨论。

在某些代码规范中遇到过这样一条要求:“尽量不要使用全局的ThreadLocal”。关于这点有两种解读。最初我的解读是,因为静态变量的生命周期和类的生命周期是一致的,而类的卸载时机可以说比较苛刻,这会导致静态ThreadLocal无法被垃圾回收,容易出现内存泄漏。另一个解读,我咨询了编写该规范的对方解释是,如果流程中改变了变量值,下次复用该流程可能导致获取到非预期的值。

但实际上,这两个解读都是不必要的,首先,静态ThreadLocal资源回收的问题,即使ThreadLocal本身无法回收,但线程中的Entry是可以通过remove清理掉的也就不会出现泄漏。第二种解读,多次复用值改变的问题,其实在调用remove后也不会出现。

而如果ThreadLocal不加static,则每次其所在类实例化时,都会有重复ThreadLocal创建。这样即使线程在访问时不出现错误也有资源浪费。

因此,ThreadLocal一般加static修饰,同时要遵循第一条及时清理。

 

该总结来源:https://zhuanlan.zhihu.com/p/91579723

 

 

 

 

 

 

 

 

 

 

 

 

 

关注
打赏
1643271353
查看更多评论
立即登录/注册

微信扫码登录

0.0408s