什么是线程局部变量?
ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量。
这个玩意有什么用处,或者说为什么要有这么一个东东?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线程都在操作同一个变量,显然是不行的,并且我们也知道volatile这个关键字也是不能保证线程安全的。那么在有一种情况之下,我们需要满足这样一个条件:变量是同一个,但是每个线程都使用同一个初始值,也就是使用同一个变量的一个新的副本。这种情况之下ThreadLocal就非常使用,比如说DAO的数据库连接,我们知道DAO是单例的,那么他的属性Connection就不是一个线程安全的变量。而我们每个线程都需要使用他,并且各自使用各自的。这种情况,ThreadLocal就比较好的解决了这个问题。
我们从源码的角度来分析这个问题。
首先定义一个ThreadLocal:
ThreadLocal<Connection> tl = ThreadLocal<Connection> Connection initConn = = DriverManager.getConnection("url, name and password"=( ==
package java.lang;import java.lang.ref.*;import java.util.concurrent.atomic.AtomicInteger;public class ThreadLocal<T> { 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<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 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差不多。
Atas ialah kandungan terperinci 什么是线程局部变量?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas



Kelas kelas Java melibatkan pemuatan, menghubungkan, dan memulakan kelas menggunakan sistem hierarki dengan bootstrap, lanjutan, dan pemuat kelas aplikasi. Model delegasi induk memastikan kelas teras dimuatkan dahulu, yang mempengaruhi LOA kelas tersuai

Artikel ini membincangkan pelaksanaan caching pelbagai peringkat di Java menggunakan kafein dan cache jambu untuk meningkatkan prestasi aplikasi. Ia meliputi persediaan, integrasi, dan faedah prestasi, bersama -sama dengan Pengurusan Dasar Konfigurasi dan Pengusiran PRA Terbaik

Artikel ini membincangkan menggunakan JPA untuk pemetaan objek-relasi dengan ciri-ciri canggih seperti caching dan pemuatan malas. Ia meliputi persediaan, pemetaan entiti, dan amalan terbaik untuk mengoptimumkan prestasi sambil menonjolkan potensi perangkap. [159 aksara]

Artikel ini membincangkan menggunakan Maven dan Gradle untuk Pengurusan Projek Java, membina automasi, dan resolusi pergantungan, membandingkan pendekatan dan strategi pengoptimuman mereka.

Artikel ini membincangkan membuat dan menggunakan perpustakaan Java tersuai (fail balang) dengan pengurusan versi dan pergantungan yang betul, menggunakan alat seperti Maven dan Gradle.
