Table of Contents
ThreadLocal in Java
ThreadLocal is a Java concurrency technique where each thread has its own variables. In other words, if multiple threads read the same code, they cannot read and write on each other thread’s local variables. This means that each thread can read and write only its own variables. This is the simplest way of achieving thread safety instead of creating immutable classes. The Java ThreadLocal variables are always private and static whose scope is within the thread.
Constructors of ThreadLocal
ThreadLocal has only a single constructor that creates an empty variable in Java.
ThreadLocal tl = new ThreadLocal();
Methods of ThreadLocal
Below are the methods of ThreadLocal in Java.
Method | Description |
---|---|
Integer get() | Returns the value of the current thread's local variable |
void remove() | Removes the value of the current thread's local variable |
void set(Integer value) | Sets the specified value to the current thread's local variable |
ThreadLocal | Creates a new thread local variable |
Benefits of ThreadLocal
- Multithreading is easier since it does not share its state across objects.
- Achieves thread-safety
- Does not require synchronization
Disadvantages of ThreadLocal
- Hides coupling among classes
- Abuses the ThreadLocal due to its visibility restriction
Example: Create, set, and get ThreadLocal
In this example, we will see how to create, set, and retrieve the value of the ThreadLocal variable. First, we create a ThreadLocal variable of Integer type. Inside the run()
method, we increment the variable value and set it using the set()
method. We can retrieve the value using the get()
method. Using the Thread class, we create 2 threads and invoke the run()
method using start()
.
public class ThreadLocalDemo { public static void main(String[] args) { ThreadDemo td = new ThreadDemo(); Thread t1 = new Thread(td); Thread t2 = new Thread(td); t1.start(); t2.start(); } } class ThreadDemo implements Runnable { private ThreadLocal<Integer> tl = new ThreadLocal<Integer>(); private int num = 10; @Override public void run() { tl.set(num++); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("ThreadLocal variable value: " + tl.get()); } }
ThreadLocal variable value: 11 ThreadLocal variable value: 10
Example: remove() method
The remove()
method deletes the value of the ThreadLocal variable for the corresponding thread.
public class ThreadLocalDemo { public static void main(String[] args) { ThreadDemo td = new ThreadDemo(); Thread t1 = new Thread(td); Thread t2 = new Thread(td); t1.start(); t2.start(); } } class ThreadDemo implements Runnable { private ThreadLocal<Integer> tl = new ThreadLocal<Integer>(); private int num = 10; @Override public void run() { tl.set(num++); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("ThreadLocal variable value: " + tl.get()); tl.remove(); System.out.println("ThreadLocal variable value: " + tl.get()); } }
ThreadLocal variable value: 10 ThreadLocal variable value: 11 ThreadLocal variable value: null ThreadLocal variable value: null
Example: initialValue() method
The initialValue()
method returns the initial value of the java ThreadLocal variable. In this example, we initialize and increment the local variable value by overriding the initialValue()
method. Hence each time we call the get()
method, it returns the incremented value of the local variable. In this way, we can initialize the values before using the set()
method.
public class ThreadInitialValueDemo { public static void main(String[] args) { ThreadEx t1 = new ThreadEx("Thread 1"); ThreadEx t2 = new ThreadEx("Thread 2"); } } class ThreadEx extends Thread { private static int num = 20; private static ThreadLocal t = new ThreadLocal() { protected Object initialValue() { return new Integer(num ++); } }; public void run() { System.out.println(t.get()); } ThreadEx(String name){ super(name); start(); } }
20 21
Supplier Implementation
There is another method of initializing the value of the ThreadLocal variable in Java by using the Supplier implementation. The Supplier interface has a static factory method which is withInitial()
. By using this, we can supply initial values to the local variable. It is always recommendable to use the lambda expression since Supplier is a functional interface.
The below example displays the current milliseconds time initialized for the local variable.
public class SupplierInitialValue { public static void main(String[] args) { Demo d1 = new Demo(); Demo d2 = new Demo(); d1.start(); d2.start(); } } class Demo extends Thread { ThreadLocal<String> tl = ThreadLocal.withInitial(() -> String.valueOf(System.currentTimeMillis())); public void run() { System.out.println(tl.get()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }
1614477848700 1614477848699
Generic ThreadLocal
Generic ThreadLocal helps to create variables of that specified type. For example, in the below code, the variable accepts only data of String type.
ThreadLocal<String> tl = new ThreadLocal<String>(); tl.set("Welcome"); String text = tl.get();
Conclusion
In this tutorial, we have discussed the ThreadLocal variable in Java which is a concurrency technique used in a multithreading environment.