Java ThreadLocal introduction
The Java ThreadLocal class is capable of keeping a single value internally per thread that accesses it.
That means, that if multiple threads share a Java ThreadLocal, each of them can set their own value inside the ThreadLocal without overwriting each other's values.
When getting the value again, each thread will get the latest value it has set on the ThreadLocal - and not any value set by other threads.

Java ThreadLocal set() and get()
public class ThreadLocalBasicExample { public static void main(String[] args) { ThreadLocal<String> threadLocal = new ThreadLocal<>(); Thread thread1 = new Thread(()->{ threadLocal.set("Thread 1"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } String value = threadLocal.get(); System.out.println("value = " + value); }); Thread thread2 = new Thread(()->{ threadLocal.set("Thread 2"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } String value = threadLocal.get(); System.out.println("value = " + value); }); thread1.start(); thread2.start(); } }
Java ThreadLocal remove() method
public class ThreadLocalRemoveExample { public static void main(String[] args) { ThreadLocal<String> threadLocal = new ThreadLocal<>(); Thread thread1 = new Thread(()->{ threadLocal.set("Thread 1"); String value = threadLocal.get(); System.out.println("1 = " + value); threadLocal.remove(); value = threadLocal.get(); System.out.println("1 = " + value); }); Thread thread2 = new Thread(()->{ threadLocal.set("Thread 2"); String value = threadLocal.get(); System.out.println("2 = " + value); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } value = threadLocal.get(); System.out.println("2 = " + value); threadLocal.remove(); value = threadLocal.get(); System.out.println("2 = " + value); }); thread1.start(); thread2.start(); } }
Java ThreadLocal with initial value
public class ThreadLocalInitialValueExample { public static void main(String[] args) { ThreadLocal<MyObject> threadLocal1 = new ThreadLocal<>(){ @Override protected MyObject initialValue() { return new MyObject(); } }; ThreadLocal<MyObject> threadLocal2 = ThreadLocal.withInitial( () -> new MyObject() ); ThreadLocal<MyObject> threadLocal3 = ThreadLocal.withInitial(MyObject::new); } }
Set value lazily on Java ThreadLocal
public class ThreadLocalLazyInitExample { public static void main(String[] args) { ThreadLocal<String> threadLocal = new ThreadLocal<>(); String value = threadLocal.get(); if(value == null){ threadLocal.set("lazily set val"); value = threadLocal.get(); } System.out.println("value = " + value); } }
Using a Java ThreadLocal from within an thread pool

Java InheritableThreadLocal
public class InheritableThreadLocalBasicExample { public static void main(String[] args) { ThreadLocal<String> threadLocal = new ThreadLocal<>(); InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>(); Thread thread1 = new Thread(() -> { System.out.println("===== Thread 1 ====="); threadLocal.set("Thread 1 - ThreadLocal"); inheritableThreadLocal.set("Thread 1 - InheritableThreadLocal"); System.out.println(threadLocal.get()); System.out.println(inheritableThreadLocal.get()); Thread childThread = new Thread( () -> { System.out.println("===== ChildThread ====="); System.out.println(threadLocal.get()); System.out.println(inheritableThreadLocal.get()); }); childThread.start(); }); thread1.start(); Thread thread2 = new Thread(() -> { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("===== Thread2 ====="); System.out.println(threadLocal.get()); System.out.println(inheritableThreadLocal.get()); }); thread2.start(); } }