public static void main(String[] args) { testFast(100); testSlow(100); }
private static void testFast(int threadLocalCount) { final FastThreadLocal<String>[] caches = new FastThreadLocal[threadLocalCount]; final Thread mainThread = Thread.currentThread(); for (int i = 0; i < threadLocalCount; i++) { caches[i] = new FastThreadLocal(); } Thread t = new FastThreadLocalThread(new Runnable() { @Override public void run() { for (int i = 0; i < threadLocalCount; i++) { caches[i].set("float.lu"); } long start = System.nanoTime(); for (int i = 0; i < threadLocalCount; i++) { for (int j = 0; j < 1000000; j++) { caches[i].get(); } } long end = System.nanoTime(); System.out.println("take[" + TimeUnit.NANOSECONDS.toMillis(end - start) + "]ms"); LockSupport.unpark(mainThread); }
}); t.start(); LockSupport.park(mainThread); }
private static void testSlow(int threadLocalCount) { final ThreadLocal<String>[] caches = new ThreadLocal[threadLocalCount]; final Thread mainThread = Thread.currentThread(); for (int i=0;i<threadLocalCount;i++) { caches[i] = new ThreadLocal(); } Thread t = new Thread(new Runnable() { @Override public void run() { for (int i=0;i<threadLocalCount;i++) { caches[i].set("float.lu"); } long start = System.nanoTime(); for (int i=0;i<threadLocalCount;i++) { for (int j=0;j<1000000;j++) { caches[i].get(); } } long end = System.nanoTime(); System.out.println("take[" + TimeUnit.NANOSECONDS.toMillis(end - start) + "]ms"); LockSupport.unpark(mainThread); }
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(); }
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); } 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; }
如果key值相等,直接返回value
如果key不相等,使用循环线性探测,一直找到最后一个元素
FastThreadLocal.get()
1 2 3 4 5 6 7 8 9 10 11 12 13
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; }
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } 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();
public FastThreadLocal() { index = InternalThreadLocalMap.nextVariableIndex(); }
UnpaddedInternalThreadLocalMap
1 2 3 4 5 6 7 8 9 10 11
Object[] indexedVariables;
public static int nextVariableIndex() { int index = nextIndex.getAndIncrement(); if (index < 0) { nextIndex.decrementAndGet(); throw new IllegalStateException("too many thread-local indexed variables"); } return index; }