1.FastThreadLocal介绍
FastThreadLocal是Netty中常用的一个工具类, FastThreadLocal所使用的InternalThreadLocalMap内部不是采用哈希表, 而是直接通过数组索引的方式返回object, 省去了哈希表的查找过程, 因此效率相比于JDK的ThreadLocal更高。
2.FastThreadLocal分析
每个FastThreadLocal带有一个类型为int的index, 该属性在整个JVM中是全局唯一的, JVM中第一个实例化的FastThreadLocal的index为0, 第二个为1。
public FastThreadLocal() {
index = InternalThreadLocalMap.nextVariableIndex();
}
public static int nextVariableIndex() {
//nextIndex是一个静态变量,每次调用nextVariableIndex()都会自增1,让后赋给FastThreadLocal的index属性
int index = nextIndex.getAndIncrement();
if (index < 0) {
nextIndex.decrementAndGet();
throw new IllegalStateException("too many thread-local indexed variables");
}
return index;
}
static final AtomicInteger nextIndex = new AtomicInteger();
InternalThreadLocalMap可以通过FastThreadLocal的index值直接通过数据下标拿到相应的object。
public final V get(InternalThreadLocalMap threadLocalMap) {
Object v = threadLocalMap.indexedVariable(index);
if (v != InternalThreadLocalMap.UNSET) {
return (V) v;
}
return initialize(threadLocalMap);
}
public Object indexedVariable(int index) {
Object[] lookup = indexedVariables;
return index < lookup.length? lookup[index] : UNSET;
}
如果要使用FastThreadLocal, 线程应该为FastThreadLocalThread, 内部使用InternalThreadLocalMap替换了JDK的ThreadLocalMap。
public static InternalThreadLocalMap get() {
Thread thread = Thread.currentThread();
if (thread instanceof FastThreadLocalThread) {
//如果是FastThreadLocalThread,那么可以直接获取该FastThreadLocalThread的InternalThreadLocalMap
return fastGet((FastThreadLocalThread) thread);
} else {
return slowGet();
}
}
private static InternalThreadLocalMap slowGet() {
//如果是普通的Thread,会先通过ThreadLocal找到Thread对应的InternalThreadLocalMap,该ThreadLocal是一个静态变量,在JVM中是唯一的
ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = UnpaddedInternalThreadLocalMap.slowThreadLocalMap;
InternalThreadLocalMap ret = slowThreadLocalMap.get();
if (ret == null) {
ret = new InternalThreadLocalMap();
slowThreadLocalMap.set(ret);
}
return ret;
}
FastThreadLocal中有一个特殊的index
private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();
这个值在整个JVM中是唯一且不变的, 并且该值也是通过InternalThreadLocalMap.nextVariableIndex()来取值的, 意味着这个值永远是0。
正常的FastThreadLocal的index是从1开始的, 因为InternalThreadLocalMap中index为0的object是一个特殊的object。
private static void addToVariablesToRemove(InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {
Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
Set<FastThreadLocal<?>> variablesToRemove;
if (v == InternalThreadLocalMap.UNSET || v == null) {
variablesToRemove = Collections.newSetFromMap(new IdentityHashMap<FastThreadLocal<?>, Boolean>());
threadLocalMap.setIndexedVariable(variablesToRemoveIndex, variablesToRemove);
} else {
variablesToRemove = (Set<FastThreadLocal<?>>) v;
}
variablesToRemove.add(variable);
}
每个FastThreadLocalThread的InternalThreadLocalMap中index为0的object是一个Set<FastThreadLocal<?>>, 这个set保存了FastThreadLocalThread所用到的所有的FastThreadLocal, 如果要删除FastThreadLocalThread中的所有Object, 直接删除set即可
public static void removeAll() {
//获取FastThreadLocalThread的InternalThreadLocalMap
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();
if (threadLocalMap == null) {
return;
}
try {
//获取index为variablesToRemoveIndex的object,也就是上面提到的index为0的特殊的object,他是一个Set
Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
if (v != null && v != InternalThreadLocalMap.UNSET) {
@SuppressWarnings("unchecked")
//将object强转为Set
Set<FastThreadLocal<?>> variablesToRemove = (Set<FastThreadLocal<?>>) v;
//获取该FastThreadLocalThread的所有的FastThreadLocal
FastThreadLocal<?>[] variablesToRemoveArray =
variablesToRemove.toArray(new FastThreadLocal[variablesToRemove.size()]);
for (FastThreadLocal<?> tlv: variablesToRemoveArray) {
//依次调用这些FastThreadLocal的remove方法
tlv.remove(threadLocalMap);
}
}
} finally {
//最后将该FastThreadLocal的InternalThreadLocalMap置为null
InternalThreadLocalMap.remove();
}
}
FastThreadLocal.removeAll()方法会在DefaultThreadFactory中被调用, 通过DefaultThreadFactory这个工厂类new出来的Thread都是FastThreadLocalThread。
public void run() {
try {
r.run();
} finally {
FastThreadLocal.removeAll();
}
}
每个线程在结束后都会调用FastThreadLocal.removeAll(), 这样该线程所有通过FastThreadLocal设置的Object在线程结束后都会被置为null, 避免了内存泄露。
3.FastThreadLocal结构分析
- InternalThreadLocalMap中并不是Entry的key-value结构, 而是Object数组
- 索引0位置存放FastThreadLocal的Set集合, 其他索引位置初始化为UNSET, 数据存入的时候更新为具体的Object
- FastThreadLocal中包含一个自增的index表示在InternalThreadLocalMap的数组中的索引位置
- Set<FastThreadLocal<?>>结构中存放FastThreadLocal的引用, 更容易解决内存泄漏的问题
4.FastThreadLocal方法分析
public class FastThreadLocalTest {
private static FastThreadLocal<Object> threadLocal =
new FastThreadLocal<Object>(){
@Override
protected Object initialValue() throws Exception {
return new Object();
}
};
// 每个线程拿到的对象都是线程独享
// 线程对对象的修改不会影响其他线程
public static void main(String[] args) {
new Thread(() -> {
// 1.获取ThreadLocalMap
// 2.直接通过索引取出对象
// 3.初始化对象, 如果没有对象的话
Object o = threadLocal.get();
System.out.println(o);
while (true){
// 1.获取ThreadLocalMap
// 2.直接通过索引set对象
// 3.remove
threadLocal.set(new Object());
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(() -> {
Object o = threadLocal.get();
System.out.println(o);
while (true){
System.out.println(threadLocal.get() == o);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
- get方法
- set方法
4.1 FastThreadLocal.get()
public final V get() {
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
Object v = threadLocalMap.indexedVariable(index);
if (v != InternalThreadLocalMap.UNSET) {
return (V) v;
}
return initialize(threadLocalMap);
}
public static InternalThreadLocalMap get() {
Thread thread = Thread.currentThread();
if (thread instanceof FastThreadLocalThread) { // 当前线程是否为 FastThreadLocalThread 类型
return fastGet((FastThreadLocalThread) thread);
} else {
return slowGet();
}
}
private static InternalThreadLocalMap fastGet(FastThreadLocalThread thread) {
InternalThreadLocalMap threadLocalMap = thread.threadLocalMap(); // 获取 FastThreadLocalThread 的 threadLocalMap 属性
if (threadLocalMap == null) {
thread.setThreadLocalMap(threadLocalMap = new InternalThreadLocalMap());
}
return threadLocalMap;
}
private static InternalThreadLocalMap slowGet() {
ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = UnpaddedInternalThreadLocalMap.slowThreadLocalMap;
InternalThreadLocalMap ret = slowThreadLocalMap.get(); // 从 JDK 原生 ThreadLocal 中获取 InternalThreadLocalMap
if (ret == null) {
ret = new InternalThreadLocalMap();
slowThreadLocalMap.set(ret);
}
return ret;
}
-
获取ThreadLocalMap
- FastThreadLocalThread: fastGet() 方法获取 FastThreadLocalThread 的threadLocalMap 属性。
- ThreadLocal: slowGet() 方法获取 InternalThreadLocalMap 就退化成 JDK 原生的 ThreadLocal 获取。
-
直接通过索引取出对象
-
初始化对象, 如果没有对象的话
4.2 FastThreadLocal.set()
public final void set(V value) {
if (value != InternalThreadLocalMap.UNSET) { // 1\. value 是否为缺省值
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get(); // 2\. 获取当前线程的 InternalThreadLocalMap
setKnownNotUnset(threadLocalMap, value); // 3\. 将 InternalThreadLocalMap 中数据替换为新的 value
} else {
remove();
}
}
- 判断 value 是否为缺省值
- 获取当前线程的InternalThreadLocalMap
- 将 InternalThreadLocalMap 中对应数据替换为新的 value
- remove
setKnownNotUnset(): 将数据添加到 InternalThreadLocalMap
private void setKnownNotUnset(InternalThreadLocalMap threadLocalMap, V value) {
if (threadLocalMap.setIndexedVariable(index, value)) {
addToVariablesToRemove(threadLocalMap, this);
}
}
public boolean setIndexedVariable(int index, Object value) {
Object[] lookup = indexedVariables;
if (index < lookup.length) {
Object oldValue = lookup[index];
lookup[index] = value;
return oldValue == UNSET;
} else {
// 扩容
expandIndexedVariableTableAndSet(index, value);
return true;
}
}
private void expandIndexedVariableTableAndSet(int index, Object value) {
Object[] oldArray = indexedVariables;
final int oldCapacity = oldArray.length;
int newCapacity = index;
newCapacity |= newCapacity >>> 1;
newCapacity |= newCapacity >>> 2;
newCapacity |= newCapacity >>> 4;
newCapacity |= newCapacity >>> 8;
newCapacity |= newCapacity >>> 16;
newCapacity ++;
Object[] newArray = Arrays.copyOf(oldArray, newCapacity);
Arrays.fill(newArray, oldCapacity, newArray.length, UNSET);
newArray[index] = value;
indexedVariables = newArray;
}
private static void addToVariablesToRemove(InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {
Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex); // 获取数组下标为 0 的元素
Set<FastThreadLocal<?>> variablesToRemove;
if (v == InternalThreadLocalMap.UNSET || v == null) {
variablesToRemove = Collections.newSetFromMap(new IdentityHashMap<FastThreadLocal<?>, Boolean>()); // 创建 FastThreadLocal 类型的 Set 集合
threadLocalMap.setIndexedVariable(variablesToRemoveIndex, variablesToRemove); // 将 Set 集合填充到数组下标 0 的位置
} else {
variablesToRemove = (Set<FastThreadLocal<?>>) v; // 如果不是 UNSET,Set 集合已存在,直接强转获得 Set 集合
}
variablesToRemove.add(variable); // 将 FastThreadLocal 添加到 Set 集合中
}
-
找到数组下标 index 位置
- 如果数组容量大于 FastThreadLocal 的 index 索引, 直接找到数组下标 index 位置将新 value 设置进去
- 在设置新的 value 之前, 将index 位置的元素取出, 如果旧元素还是UNSET缺省对象, 返回成功
-
expandIndexedVariableTableAndSet(): 扩容
-
addToVariablesToRemove(): 向 InternalThreadLocalMap 添加完数据之后, 将 FastThreadLocal 对象保存到待清理的 Set 中文章来源:https://www.toymoban.com/news/detail-416819.html
remove():文章来源地址https://www.toymoban.com/news/detail-416819.html
public final void remove() {
remove(InternalThreadLocalMap.getIfSet());
}
public static InternalThreadLocalMap getIfSet() {
Thread thread = Thread.currentThread();
if (thread instanceof FastThreadLocalThread) {
return ((FastThreadLocalThread) thread).threadLocalMap();
}
return slowThreadLocalMap.get();
}
public final void remove(InternalThreadLocalMap threadLocalMap) {
if (threadLocalMap == null) {
return;
}
Object v = threadLocalMap.removeIndexedVariable(index); // 删除数组下标 index 位置对应的 value
removeFromVariablesToRemove(threadLocalMap, this); // 从数组下标 0 的位置取出 Set 集合,并删除当前 FastThreadLocal
if (v != InternalThreadLocalMap.UNSET) {
try {
onRemoval((V) v); // 空方法,用户可以继承实现
} catch (Exception e) {
PlatformDependent.throwException(e);
}
}
}
- 调用 InternalThreadLocalMap.getIfSet() 获取当前 InternalThreadLocalMap
- 如果是 FastThreadLocalThread 类型, 直接取 FastThreadLocalThread 中 threadLocalMap 属性
- 如果是普通Thread, 从 ThreadLocal 类型的 slowThreadLocalMap 中获取
- InternalThreadLocalMap 会从数组中定位到下标 index 位置的元素, 覆盖为缺省对象 UNSET
- 清理当前的 FastThreadLocal 对象, InternalThreadLocalMap 会取出数组下标 0 位置的 Set 集合, 删除当前FastThreadLocal
到了这里,关于[Netty] FastThreadLocal (十四)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!