Java Multithreading Tutorial With Example

ThreadLocal variable in JAVA with Example

This guide will help you understand about ThreadLocal variable and how to create and access the ThreadLocal variable in Java.

You will learn:
– What is the ThreadLocal variable?
– Why do you need the ThreadLocal variable?
– How to create and access a ThreadLocal variable?

Few more Concurrent related articles from Codedelay

ConcurrentHashMap with example.
CompletableFuture Examples

What is the ThreadLocal variable in JAVA?

The ThreadLocal variable allows you to store data in the execution context of each thread.

Thus each thread can have its own instance of data that can only be read and written by the same thread.

Benefits of using ThreadLocal variable

  • A ThreadLocal variable is essentially a container that contains a copy of the variable for each thread created from a class. Therefore, other threads can’t read and write data from that ThreadLocal variable.
  • Apart from synchronization, ThreadLocal is another way to achieve thread-safety in Java.

How to create a ThreadLocal variable

To create a ThreadLocal object, we can use the no-arg constructor of the ThreadLocal class.

ThreadLocal<String> threadLocal = new ThreadLocal<>();

In the above example, I have created threadLocal variable which will store string value.

Once you have created the instance of ThreadLocal class, you can set the value using set() method.

threadLocal.set(Thread.currentThread().getName());

To value the value you can call get() from the threadLocal reference variable.

threadLocal.get();

Now let me show you how the final code looks like.

package com.codedelay.concurrency;

import java.util.concurrent.TimeUnit;

public class Task implements Runnable {
	public static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>();

	public static void set(String str) {
		THREAD_LOCAL.set(str);
	}

	public static void unset() {
		THREAD_LOCAL.remove();
	}

	public static String get() {
		return THREAD_LOCAL.get();
	}
	
	@Override
	public void run() {
		try {
			Task.set(Thread.currentThread().getName());
			TimeUnit.SECONDS.sleep(3);
			System.out.println(Task.get());
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
package com.codedelay.concurrency;

public class ThreadLocalDemoApp {

	public static void main(String[] args) {
		Task task = new Task();
		Thread firstTask = new Thread(task, "firstTask");
		Thread secondTask = new Thread(task, "secondTask");
		
		firstTask.start();
		secondTask.start();
		
		try {
			firstTask.join();
			secondTask.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

ThreadLocal as an alternative option to synchronization

ThreadLocal is also useful when you want to avoid synchronization due to performance cost.

Let’s take an example of SimpleDateFormat.

SimpleDateFormat is not a thread-safe class that means in a multithreaded environment data inconsistency is the challenge with SimpleDateFormat.

private DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");

	public Date convertStringToDate(String inputDate) throws ParseException {
		Date date;
		synchronized (dateFormat) {
			date = dateFormat.parse(inputDate);
		}
		return date;
	}

In the above example, you may notice that DateFormat is not thread-safe.

Therefore, we have added a synchronized block to avoid data inconsistency issues.

Let’s change the implementation using ThreadLocal.

package com.codedelay.concurrency;

import java.text.SimpleDateFormat;
import java.util.Date;

public class DateFormatExample implements Runnable {

	static ThreadLocal<SimpleDateFormat> threadLocalDate = new ThreadLocal<SimpleDateFormat>() {
		@Override
		protected SimpleDateFormat initialValue() {
			return new SimpleDateFormat("dd/MM/yyyy");
		}
	};

	public String formatDate(Date date) {
		return threadLocalDate.get().format(date);
	}

	public static void main(String[] args) {
		DateFormatExample td = new DateFormatExample();
        Thread threadA = new Thread(td, "Thread-A");
        Thread threadB = new Thread(td, "Thread-B");
        threadA.start();
        threadB.start();
    }

    @Override
    public void run() {
        System.out.println("Current Thread " 
                          + Thread.currentThread().getName());
        System.out.println("Formatted date is " 
                         + formatDate(new Date()));
    } 

}

The output of the above program would be:

Current Thread Thread-A
Current Thread Thread-B
Formatted date is 04/08/2019
Formatted date is 04/08/2019

In the above program, you might have noticed that we have overridden initialValue() to set date.

Let’s take a look at the initialValue() method of ThreadLocal class.

The initial value of a ThreadLocal variable

In order to provide the initial value to the ThreadLocal variable, we can use the initialValue() method provided by the ThreadLocal class.

public static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>() {
		protected String initialValue() {
			return "Hello world from code delay";
		};
	};

You can also use the lambda expression to simplify the above code block.

public static final ThreadLocal<String> THREAD_LOCAL_ = ThreadLocal.withInitial(() -> {
		return "\"Hello world from code delay\"";
	});

Once you provide an initial value, all the threads will the same value when they call get() before set()

Conclusion

Apart from synchronization, ThreadLocal in Java is an alternative way to provide thread-safety.

ThreadLocal lets each thread to have its own local variable. We can also initialize ThreadLocal values using the initialValue() method.

Click to rate this post!
[Total: 0 Average: 0]

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.