ThreadLocal源码分析
来源:互联网 发布:赢时胜软件 编辑:程序博客网 时间:2024/06/06 09:06
本篇文章将结合ThreadLocal源码深入探究ThreadLocal内部实现,期待对ThreadLocal有更透彻的了解。
类定义
先看看ThreadLocal类的定义:
package java.lang;public class ThreadLocal<T> { /** * Creates a thread local variable. * @see #withInitial(java.util.function.Supplier) */ public ThreadLocal() { }}
set方法
ThreadLocal 的set方法如下:
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value);}
getMap方法:
ThreadLocalMap getMap(Thread t) { return t.threadLocals;}
createMap方法:
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue);}
在ThreadLocal的set方法时,首先通过ThreadLocal.getMap(Thread t)方法获取一个和当前线程相关的ThreadLocalMap,并将其赋值给ThreadLocalMap map变量,如果获取到的ThreadLocalMap对象不为空,则调用ThreadLocalMap 的set方法将value保存起来,否则通过createMap方法创建。
Thread类threadLocals 变量
在Thread 类内部有一个ThreadLocal.ThreadLocalMap 类型的变量 inheritableThreadLocals,如下:
package java.lang;public class Thread implements Runnable { /* * InheritableThreadLocal values pertaining to this thread. This map is * maintained by the InheritableThreadLocal class. */ ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;}
ThreadLocalMap类
ThreadLocalMap是ThreadLocal的一个静态内部类,它的结构如下:
static class ThreadLocalMap { static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } private static final int INITIAL_CAPACITY = 16; private Entry[] table; private int size = 0; private int threshold; // Default to 0 ... /** * Construct a new map initially containing (firstKey, firstValue). * ThreadLocalMaps are constructed lazily, so we only create * one when we have at least one entry to put in it. */ 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); } /** * Get the entry associated with key. This method * itself handles only the fast path: a direct hit of existing * key. It otherwise relays to getEntryAfterMiss. This is * designed to maximize performance for direct hits, in part * by making this method readily inlinable. * * @param key the thread local object * @return the entry associated with key, or null if no such */ private Entry getEntry(ThreadLocal<?> key) { int i = key.threadLocalHashCode & (table.length - 1); Entry e = table[i]; if (e != null && e.get() == key) return e; else return getEntryAfterMiss(key, i, e); } /** * Version of getEntry method for use when key is not found in * its direct hash slot. * * @param key the thread local object * @param i the table index for key's hash code * @param e the entry at table[i] * @return the entry associated with key, or null if no such */ private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) { Entry[] tab = table; int len = tab.length; while (e != null) { ThreadLocal<?> k = e.get(); if (k == key) return e; if (k == null) expungeStaleEntry(i); else i = nextIndex(i, len); e = tab[i]; } return null; } /** * Set the value associated with key. * * @param key the thread local object * @param value the value to be set */ private void set(ThreadLocal<?> key, Object value) { // We don't use a fast path as with get() because it is at // least as common to use set() to create new entries as // it is to replace existing ones, in which case, a fast // path would fail more often than not. Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { ThreadLocal<?> k = e.get(); if (k == key) { e.value = value; return; } if (k == null) { replaceStaleEntry(key, value, i); return; } } tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); } /** * Remove the entry for key. */ private void remove(ThreadLocal<?> key) { Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { if (e.get() == key) { e.clear(); expungeStaleEntry(i); return; } } }}
get()方法
接下来再看一下ThreadLocal类中的get()方法:
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();}
再来看setInitialValue()方法:
private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
再看看 initialValue 方法
protected T initialValue() { return null;}
remove方法
最后看看ThreadLocal类中的remove()方法
/** * Removes the current thread's value for this thread-local * variable. If this thread-local variable is subsequently * {@linkplain #get read} by the current thread, its value will be * reinitialized by invoking its {@link #initialValue} method, * unless its value is {@linkplain #set set} by the current thread * in the interim. This may result in multiple invocations of the * {@code initialValue} method in the current thread. * * @since 1.5 */ public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }
总结
ThreadLocal实现线程隔离的核心,就在于ThreadLocalMap这个类。ThreadLocalMap是ThreadLocal类的一个静态内部类,它实现了键值对的设置和获取(类似HashMap),每个线程中都有一个独立的ThreadLocalMap副本,它所存储的值,只能被当前线程读取和修改。ThreadLocal类通过操作每一个线程特有的ThreadLocalMap副本,从而实现了变量访问在不同线程中的隔离。
- ThreadLocal源码分析
- Threadlocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析解密
- ThreadLocal源码分析
- java-----ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal的源码分析
- android-----ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal的源码分析
- ThreadLocal源码简单分析
- SparseArray代替HashMap
- python的socket编程之udp编程
- 【BZOJ2875】[Noi2012]随机数生成器【矩阵快速幂】
- c++语法——类和对象的学习(1)
- 浙大 PAT Advanced level 1020. Tree Traversals (25)
- ThreadLocal源码分析
- python中操作数据库中游标的使用方法
- 2016年武汉科技大学邀请赛网络赛 J题
- 动态规划 中级题解 路径记录
- UITextField限制输入字数高亮状态下输入框内真实类容与textFiled(解决中文输入问题)
- 用fiddler模拟网络请求超时
- Android-Activity生命周期的理解
- android WebView拦截js弹窗界面无响应问题
- 110.[Leetcode]Balanced Binary Tree