您的位置:首页 > 编程语言 > Java开发

ThreadLocal(2)--ThreadLocal源码(jdk1.7)

2016-03-28 22:15 399 查看
本文通过对ThreadLocal源码(jdk1.7)解析来加深对ThreaLocal类理解

源代码如下:

[java] view
plain copy

package java.lang;

import java.lang.ref.*;

import java.util.concurrent.atomic.AtomicInteger;

public class ThreadLocal<T> {

private final int threadLocalHashCode = nextHashCode(); //ThreadLocal实例hash值,用来区分不同实例

private static AtomicInteger nextHashCode = //可以看作hash值的一个基值

new AtomicInteger();

private static final int HASH_INCREMENT = 0x61c88647; //hash值每次增加量

private static int nextHashCode() {

return nextHashCode.getAndAdd(HASH_INCREMENT);

}

//初始化函数

protected T initialValue() {

return null;

}

//无参构造函数

public ThreadLocal() {

}

//注意:每个线程中都是有一个ThreadLocalMap对象,它属于Map类型,其中key为ThreadLocal对象,value为某个对象。

//从当前线程的ThreadLocalMap中取出 key为当前ThreadLocal对象 的value对象,其实key值与ThreadLocal的threadLocalHashCode值有关

public T get() {

Thread t = Thread.currentThread(); //得到当前线程

ThreadLocalMap map = getMap(t); //得到当前线程的ThreadLocalMap对象

if (map != null) { //如果map不为null,

ThreadLocalMap.Entry e = map.getEntry(this); //得到map中Entry实体对象;

if (e != null) //如果e不为空,则取出Entry对象中的value值,然后返回

return (T)e.value;

}

return setInitialValue(); //如果map为null,则创建ThreadLocalMap对象,

//并且创建一个空的T对象放到map中,最后返回null

}

private T setInitialValue() {

T value = initialValue();

Thread t = Thread.currentThread(); //得到当前线程

ThreadLocalMap map = getMap(t); //得到当前线程的ThreadLocalMap对象

if (map != null) //map不为空,则将value放到map

map.set(this, value);

else

createMap(t, value); //否则创建map,然后将value放到map中

return value;

}

//把value放到当前线程的ThreadLocalMap对象中去,其中key值与当前ThreadLocal对象的threadLocalHashCode值有关

public void set(T value) {

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);

if (map != null)

map.set(this, value);

else

createMap(t, value);

}

//删除当前线程的 ThreadLocalMap对象中 key为当前ThreadLocal 的Entry(包含key/value)

public void remove() {

ThreadLocalMap m = getMap(Thread.currentThread());

if (m != null)

m.remove(this);

}

//取得TheadLocalMap

ThreadLocalMap getMap(Thread t) {

return t.threadLocals;

}

//创建TheadLocalMap

void createMap(Thread t, T firstValue) {

t.threadLocals = new ThreadLocalMap(this, firstValue);

}

static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {

return new ThreadLocalMap(parentMap);

}

T childValue(T parentValue) {

throw new UnsupportedOperationException();

}

//静态内部类ThreadLcoalMap

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

private void setThreshold(int len) {

threshold = len * 2 / 3;

}

private static int nextIndex(int i, int len) {

return ((i + 1 < len) ? i + 1 : 0);

}

private static int prevIndex(int i, int len) {

return ((i - 1 >= 0) ? i - 1 : len - 1);

}

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);

}

private ThreadLocalMap(ThreadLocalMap parentMap) {

Entry[] parentTable = parentMap.table;

int len = parentTable.length;

setThreshold(len);

table = new Entry[len];

for (int j = 0; j < len; j++) {

Entry e = parentTable[j];

if (e != null) {

ThreadLocal key = e.get();

if (key != null) {

Object value = key.childValue(e.value);

Entry c = new Entry(key, value);

int h = key.threadLocalHashCode & (len - 1);

while (table[h] != null)

h = nextIndex(h, len);

table[h] = c;

size++;

}

}

}

}

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;

}

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();

}

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;

}

}

}

private void replaceStaleEntry(ThreadLocal key, Object value,

int staleSlot) {

Entry[] tab = table;

int len = tab.length;

Entry e;

// Back up to check for prior stale entry in current run.

// We clean out whole runs at a time to avoid continual

// incremental rehashing due to garbage collector freeing

// up refs in bunches (i.e., whenever the collector runs).

int slotToExpunge = staleSlot;

for (int i = prevIndex(staleSlot, len);

(e = tab[i]) != null;

i = prevIndex(i, len))

if (e.get() == null)

slotToExpunge = i;

// Find either the key or trailing null slot of run, whichever

// occurs first

for (int i = nextIndex(staleSlot, len);

(e = tab[i]) != null;

i = nextIndex(i, len)) {

ThreadLocal k = e.get();

// If we find key, then we need to swap it

// with the stale entry to maintain hash table order.

// The newly stale slot, or any other stale slot

// encountered above it, can then be sent to expungeStaleEntry

// to remove or rehash all of the other entries in run.

if (k == key) {

e.value = value;

tab[i] = tab[staleSlot];

tab[staleSlot] = e;

// Start expunge at preceding stale entry if it exists

if (slotToExpunge == staleSlot)

slotToExpunge = i;

cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);

return;

}

// If we didn't find stale entry on backward scan, the

// first stale entry seen while scanning for key is the

// first still present in the run.

if (k == null && slotToExpunge == staleSlot)

slotToExpunge = i;

}

// If key not found, put new entry in stale slot

tab[staleSlot].value = null;

tab[staleSlot] = new Entry(key, value);

// If there are any other stale entries in run, expunge them

if (slotToExpunge != staleSlot)

cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);

}

private int expungeStaleEntry(int staleSlot) {

Entry[] tab = table;

int len = tab.length;

// expunge entry at staleSlot

tab[staleSlot].value = null;

tab[staleSlot] = null;

size--;

// Rehash until we encounter null

Entry e;

int i;

for (i = nextIndex(staleSlot, len);

(e = tab[i]) != null;

i = nextIndex(i, len)) {

ThreadLocal k = e.get();

if (k == null) {

e.value = null;

tab[i] = null;

size--;

} else {

int h = k.threadLocalHashCode & (len - 1);

if (h != i) {

tab[i] = null;

// Unlike Knuth 6.4 Algorithm R, we must scan until

// null because multiple entries could have been stale.

while (tab[h] != null)

h = nextIndex(h, len);

tab[h] = e;

}

}

}

return i;

}

private boolean cleanSomeSlots(int i, int n) {

boolean removed = false;

Entry[] tab = table;

int len = tab.length;

do {

i = nextIndex(i, len);

Entry e = tab[i];

if (e != null && e.get() == null) {

n = len;

removed = true;

i = expungeStaleEntry(i);

}

} while ( (n >>>= 1) != 0);

return removed;

}

private void rehash() {

expungeStaleEntries();

// Use lower threshold for doubling to avoid hysteresis

if (size >= threshold - threshold / 4)

resize();

}

private void resize() {

Entry[] oldTab = table;

int oldLen = oldTab.length;

int newLen = oldLen * 2;

Entry[] newTab = new Entry[newLen];

int count = 0;

for (int j = 0; j < oldLen; ++j) {

Entry e = oldTab[j];

if (e != null) {

ThreadLocal k = e.get();

if (k == null) {

e.value = null; // Help the GC

} else {

int h = k.threadLocalHashCode & (newLen - 1);

while (newTab[h] != null)

h = nextIndex(h, newLen);

newTab[h] = e;

count++;

}

}

}

setThreshold(newLen);

size = count;

table = newTab;

}

private void expungeStaleEntries() {

Entry[] tab = table;

int len = tab.length;

for (int j = 0; j < len; j++) {

Entry e = tab[j];

if (e != null && e.get() == null)

expungeStaleEntry(j);

}

}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: