spring为什么要用线程安全,spring是怎么保证线程安全的

首页 > 技术 > 作者:YD1662023-11-03 11:47:18

ThreadLocal的set()与remove()函数要比get()的实现还要简单,都只是通过getMap()来获得ThreadLocalMap然后对其进行操作。

spring为什么要用线程安全,spring是怎么保证线程安全的(5)

getMap()函数与createMap()函数的实现也十分简单,但是通过观察这两个函数可以发现一个秘密:ThreadLocalMap是存放在Thread中的。

spring为什么要用线程安全,spring是怎么保证线程安全的(6)

仔细想想其实就能够理解这种设计的思想。有一种普遍的方法是通过一个全局的线程安全的Map来存储各个线程的变量副本,但是这种做法已经完全违背了ThreadLocal的本意,设计ThreadLocal的初衷就是为了避免多个线程去并发访问同一个对象,尽管它是线程安全的。而在每个Thread中存放与它关联的ThreadLocalMap是完全符合ThreadLocal的思想的,当想要对线程局部变量进行操作时,只需要把Thread作为key来获得Thread中的ThreadLocalMap即可。这种设计相比采用一个全局Map的方法会多占用很多内存空间,但也因此不需要额外的采取锁等线程同步方法而节省了时间上的消耗。

ThreadLocal中的内存泄漏

我们要考虑一种会发生内存泄漏的情况,如果ThreadLocal被设置为null后,而且没有任何强引用指向它,根据垃圾回收的可达性分析算法,ThreadLocal将会被回收。这样一来,ThreadLocalMap中就会含有key为null的Entry,而且ThreadLocalMap是在Thread中的,只要线程迟迟不结束,这些无法访问到的value会形成内存泄漏。为了解决这个问题,ThreadLocalMap中的getEntry()、set()和remove()函数都会清理key为null的Entry,以下面的getEntry()函数的源码为例。

spring为什么要用线程安全,spring是怎么保证线程安全的(7)

在上文中我们发现了ThreadLocalMap的key是一个弱引用,那么为什么使用弱引用呢?使用强引用key与弱引用key的差别如下:

但要注意的是,ThreadLocalMap仅仅含有这些被动措施来补救内存泄漏问题。如果你在之后没有调用ThreadLocalMap的set()、getEntry()和remove()函数的话,那么仍然会存在内存泄漏问题。

在使用线程池的情况下,如果不及时进行清理,内存泄漏问题事小,甚至还会产生程序逻辑上的问题。所以,为了安全地使用ThreadLocal,必须要像每次使用完锁就解锁一样,在每次使用完ThreadLocal后都要调用remove()来清理无用的Entry

spring为什么要用线程安全,spring是怎么保证线程安全的(8)

上一页123下一页

栏目热文

文档排行

本站推荐

Copyright © 2018 - 2021 www.yd166.com., All Rights Reserved.