Mastering Java ThreadLocal: Core Operations, Map Structure, and Practical Examples
This article explains Java's ThreadLocal mechanism, detailing its internal ThreadLocalMap structure, core set/get/remove operations with full code examples, and demonstrates how multiple ThreadLocal variables are stored per thread, providing a clear understanding of thread‑local storage in backend development.
ThreadLocalclass contains a static inner class ThreadLocalMap, which implements the thread‑isolation mechanism. Each Thread has a ThreadLocalMap instance.
public class Thread implements Runnable {
// ThreadLocal variable stored in Thread class
ThreadLocal.ThreadLocalMap threadLocals = null;
}ThreadLocal Core Operations
set operation
public void set(T value) {
// Get current thread
Thread t = Thread.currentThread();
// Get current thread's ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null) {
// If map exists, set value
map.set(this, value);
} else {
// If map does not exist, create map and set value
createMap(t, value);
}
}
// ThreadLocalMap's set method
private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
// Compute index using ThreadLocal's hashCode
int i = key.threadLocalHashCode & (len - 1);
// Handle hash collision, linear probing
for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
// If same key, update value
if (k == key) {
e.value = value;
return;
}
// If key is null, it has been GC'd, replace entry
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
// Create new Entry
tab[i] = new Entry(key, value);
size++;
// Check if resize needed
if (!cleanSomeSlots(i, size) && size >= threshold)
rehash();
}get operation
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();
}
// ThreadLocalMap's getEntry method
private Entry getEntry(ThreadLocal<?> key) {
// Compute index
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
// If found and key matches, return
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}remove operation
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
// ThreadLocalMap's remove method
private void remove(ThreadLocal<?> key) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len - 1);
// Find and delete Entry
for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
if (e.get() == key) {
// Clear reference
e.clear();
// Clean up stale entry
expungeStaleEntry(i);
return;
}
}
}It can be seen that ThreadLocal's get, set, and remove methods ultimately operate on the data stored in ThreadLocalMap.
ThreadLocalMap Structure
ThreadLocalMap contains a static inner class Entry that extends WeakReference<ThreadLocal?>. The key is a weak reference, while the value is a strong reference.
static class ThreadLocalMap {
// Entry extends WeakReference, key is weak reference
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value; // value is strong reference
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;
...
}Summary
ThreadLocal stores data in a Thread's ThreadLocalMap. ThreadLocalMap holds an Entry array that can store multiple ThreadLocal objects; a single thread can hold several ThreadLocal values via the same ThreadLocalMap. Each ThreadLocal object caches only one variable value.
One thread can set multiple ThreadLocal variables:
public class ThreadLocalTest {
// Define multiple ThreadLocal objects
private static final ThreadLocal<String> nameThreadLocal = new ThreadLocal<>();
private static final ThreadLocal<Integer> ageThreadLocal = new ThreadLocal<>();
private static final ThreadLocal<User> userInfoThreadLocal = new ThreadLocal<>();
public void setVal() {
// Same thread can set multiple ThreadLocal values
nameThreadLocal.set("xuanwu");
ageThreadLocal.set(18);
userInfoThreadLocal.set(new User("xuanwu", 18));
// Get each ThreadLocal value
String name = nameThreadLocal.get();
Integer age = ageThreadLocal.get();
User user = userInfoThreadLocal.get();
}
}Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Xuanwu Backend Tech Stack
Primarily covers fundamental Java concepts, mainstream frameworks, deep dives into underlying principles, and JVM internals.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
