java 线程局部变量_什么是线程局部变量?

ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量。

这个玩意有什么用处,或者说为什么要有这么一个东东?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线程都在操作同一个变量,显然是不行的,并且我们也知道volatile这个关键字也是不能保证线程安全的。那么在有一种情况之下,我们需要满足这样一个条件:变量是同一个,但是每个线程都使用同一个初始值,也就是使用同一个变量的一个新的副本。这种情况之下ThreadLocal就非常使用,比如说DAO的数据库连接,我们知道DAO是单例的,那么他的属性Connection就不是一个线程安全的变量。而我们每个线程都需要使用他,并且各自使用各自的。这种情况,ThreadLocal就比较好的解决了这个问题。

我们从源码的角度来分析这个问题。

首先定义一个ThreadLocal:

ThreadLocal tl = ThreadLocal Connection initConn = = DriverManager.getConnection("url, name and password"=( ==

package java.lang;import java.lang.ref.*;import java.util.concurrent.atomic.AtomicInteger;public class ThreadLocal { private final int threadLocalHashCode = nextHashCode(); private static AtomicInteger nextHashCode =new AtomicInteger();private static final int HASH_INCREMENT = 0x61c88647;private static int nextHashCode() {return nextHashCode.getAndAdd(HASH_INCREMENT);

}protected T initialValue() {return null;

}public ThreadLocal() {

}public T get() {

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);if (map != null) {

ThreadLocalMap.Entry e = map.getEntry(this);if (e != null)return (T)e.value;

}return setInitialValue();

}private T setInitialValue() {

T value = initialValue();

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);if (map != null)

map.set(this, value);elsecreateMap(t, value);return value;

}public void set(T value) {

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);if (map != null)

map.set(this, value);elsecreateMap(t, value);

} public void remove() {

ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null)

m.remove(this);

}ThreadLocalMap getMap(Thread t) {return t.threadLocals;

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

}static class ThreadLocalMap {static class Entry extends WeakReference {/** 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 0private 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;elsereturn 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);elsei = nextIndex(i, len);

e = tab[i];

}return null;

}private void set(ThreadLocal key, Object value) {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;int slotToExpunge = staleSlot;for (int i = prevIndex(staleSlot, len);

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

i = prevIndex(i, len))if (e.get() == null)

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

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

i = nextIndex(i, len)) {

ThreadLocal k = e.get();if (k == key) {

e.value = value;

tab[i] = tab[staleSlot];

tab[staleSlot] = e;if (slotToExpunge == staleSlot)

slotToExpunge = i;

cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);return;

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

slotToExpunge = i;

}tab[staleSlot].value = null;

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

cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);

}private int expungeStaleEntry(int staleSlot) {

Entry[] tab = table;int len = tab.length;tab[staleSlot].value = null;

tab[staleSlot] = null;

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

}

}

}

}

这样子,都是用同一个连接,但是每个连接都是新的,是同一个连接的副本。

那么实现机制是如何的呢?

1、每个Thread对象内部都维护了一个ThreadLocalMap这样一个ThreadLocal的Map,可以存放若干个ThreadLocal

/* ThreadLocal values pertaining to this thread. This map is maintained

* by the ThreadLocal class. */ThreadLocal.ThreadLocalMap threadLocals = null;

2、当我们在调用get()方法的时候,先获取当前线程,然后获取到当前线程的ThreadLocalMap对象,如果非空,那么取出ThreadLocal的value,否则进行初始化,初始化就是将initialValue的值set到ThreadLocal中。

public T get() {

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);if (map != null) {

ThreadLocalMap.Entry e = map.getEntry(this);if (e != null)return (T)e.value;

}return setInitialValue();

}

3、当我们调用set()方法的时候,很常规,就是将值设置进ThreadLocal中。

4、总结:当我们调用get方法的时候,其实每个当前线程中都有一个ThreadLocal。每次获取或者设置都是对该ThreadLocal进行的操作,是与其他线程分开的。

5、应用场景:当很多线程需要多次使用同一个对象,并且需要该对象具有相同初始化值的时候最适合使用ThreadLocal。

6、其实说再多也不如看一下源码来得清晰。如果要看源码,其中涉及到一个WeakReference和一个Map,这两个地方需要了解下,这两个东西分别是a.Java的弱引用,也就是GC的时候会销毁该引用所包裹(引用)的对象,这个threadLocal作为key可能被销毁,但是只要我们定义成他的类不卸载,tl这个强引用就始终引用着这个ThreadLocal的,永远不会被gc掉。b.和HashMap差不多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值