作者:神秘的霸气沉默_168 | 来源:互联网 | 2023-09-23 05:52
文章目录ThreadLocal使用和源码分析概述基本使用源码分析ThreadThreadLocalThreadLocalMap内存泄漏问题ThreadLocal使用和源码分析概述
文章目录
- ThreadLocal使用和源码分析
- 概述
- 基本使用
- 源码分析
- Thread
- ThreadLocal
- ThreadLocalMap
- 内存泄漏问题
ThreadLocal使用和源码分析
概述
- ThreadLocal即线程局部变量。
- ThreadLocal提供线程的局部变量,每个线程可以通过了get/set方法对局部变量进行操作。
- 局部变量不会和其他线程的局部变量有冲突,实现了线程的数据隔离。
- Thread和ThreadLocal关系:
- Thread内部持有ThreadLocalMap类型的成员变量threadLocals。
- ThreadLocal是负责操作线程局部变量的管理类,有
get()、set()、remove()
方法负责获取、设置、清除数据。 - ThreadLocalMap是ThreadLocal的内部类,用于存储线程的局部变量,内部维护一个Entry数组,键值对结构,键为ThreadLocal类型,值为Object类型。
基本使用
private static ThreadLocal<String> mThreadLocal &#61; new ThreadLocal<>();static class A implements Runnable {&#64;Overridepublic void run() {mThreadLocal.set("线程A");mThreadLocal.set("线程AAA");System.out.println(mThreadLocal.get());}
}static class B implements Runnable {&#64;Overridepublic void run() {mThreadLocal.set("线程B");System.out.println(mThreadLocal.get());}
}public static void main(String[] args) {mThreadLocal.set("线程main");new Thread(new A()).start();new Thread(new B()).start();System.out.println(mThreadLocal.get());
}
输出信息&#xff1a;
线程main
线程AAA
线程B
源码分析
Thread
public class Thread implements Runnable {ThreadLocal.ThreadLocalMap threadLocals &#61; null;private void exit() { threadLocals &#61; null;}
}
ThreadLocal
public class ThreadLocal<T> {void createMap(Thread t, T firstValue) {t.threadLocals &#61; new ThreadLocalMap(this, firstValue);}ThreadLocalMap getMap(Thread t) {return t.threadLocals;}public void set(T value) {Thread t &#61; Thread.currentThread();ThreadLocalMap map &#61; getMap(t);if (map !&#61; null)map.set(this, value);elsecreateMap(t, value);}public T get() {Thread t &#61; Thread.currentThread();ThreadLocalMap map &#61; getMap(t);if (map !&#61; null) {ThreadLocalMap.Entry e &#61; map.getEntry(this);if (e !&#61; null) {T result &#61; (T)e.value;return result;}}return setInitialValue();}private T setInitialValue() {T value &#61; initialValue();Thread t &#61; Thread.currentThread();ThreadLocalMap map &#61; getMap(t);if (map !&#61; null)map.set(this, value);elsecreateMap(t, value);return value;}public void remove() {ThreadLocalMap m &#61; getMap(Thread.currentThread());if (m !&#61; null)m.remove(this);}private void remove(ThreadLocal<?> key) {Entry[] tab &#61; table;int len &#61; tab.length;int i &#61; key.threadLocalHashCode & (len-1);for (Entry e &#61; tab[i];e !&#61; null;e &#61; tab[i &#61; nextIndex(i, len)]) {if (e.get() &#61;&#61; key) {e.clear();expungeStaleEntry(i);return;}}}
}
ThreadLocalMap
static class ThreadLocalMap {static class Entry extends WeakReference<ThreadLocal<?>> {Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value &#61; v;}}private static final int INITIAL_CAPACITY &#61; 16;private Entry[] table;private int threshold; private void setThreshold(int len) {threshold &#61; len * 2 / 3;}ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {table &#61; new Entry[INITIAL_CAPACITY];int i &#61; firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);table[i] &#61; new Entry(firstKey, firstValue);size &#61; 1;setThreshold(INITIAL_CAPACITY);}private void set(ThreadLocal<?> key, Object value) { Entry[] tab &#61; table;int len &#61; tab.length;int i &#61; key.threadLocalHashCode & (len-1);for (Entry e &#61; tab[i];e !&#61; null;e &#61; tab[i &#61; nextIndex(i, len)]) {ThreadLocal<?> k &#61; e.get();if (k &#61;&#61; key) {e.value &#61; value;return;}if (k &#61;&#61; null) {replaceStaleEntry(key, value, i);return;}}tab[i] &#61; new Entry(key, value);int sz &#61; &#43;&#43;size;if (!cleanSomeSlots(i, sz) && sz >&#61; threshold)rehash();}private Entry getEntry(ThreadLocal<?> key) {int i &#61; key.threadLocalHashCode & (table.length - 1);Entry e &#61; table[i];if (e !&#61; null && e.get() &#61;&#61; key)return e;elsereturn getEntryAfterMiss(key, i, e);}
}
内存泄漏问题
ThreadLocalMap内部维护了一个Entry数组&#xff0c;在没有执行remove的情况下&#xff0c;将ThreadLocal设置为null&#xff0c;下次GC时&#xff0c;key是弱引用会被回收&#xff0c;value是强引用并指向对象就会一直存在内存中&#xff0c;这样会发生内存泄露。
所以ThreadLocal使用后需要及时remove掉。