Welcome to my new article on Java Programming. Today we will talk about Java ThreadLocal class and how this can be used with the help of a simple demo.

About the Usecase…

I have a web application where multiple users can log in at a time and access the resources. Each of these users is assigned with a session and whatever they do will come under the session scope. Whenever a user logs in or hits an endpoint, a login thread capture it and processes the request and updates the session assigned to the user with user details which can be retrieved later on subsequent requests.

About the Solution…

This is a simple problem and we can create a session container as a global object. This session object can be shared across all the login threads or any other threads which handle the subsequent requests. The real problem here is thread-safety. How can we make the container thread-safe and shared across multiple threads at the same time?

About Thread Local…

By using Thread Local programming method we can make the global objects local to a thread which is being executed.

This means if there are three login threads all three will get its own copy of the Thread Local global variable. The updates done by one thread will not impact the execution of other threads.

Creating Thread Local…


public final class SessionContextHolder {
private static final SessionContextHolder sessionContextHolder;
static { sessionContextHolder = new SessionContextHolder(); }
public static SessionContextHolder getInstance() { return sessionContextHolder; }
private final ThreadLocal<Session> sessionContext;
private SessionContextHolder() {
super();
sessionContext = new ThreadLocal<>();
}
}

As you can see the session context holder is following a singleton pattern and so across the application, there will be only one instance and inside that, we are creating a ThreadLocal<Session> instance. The sessionContext will hold the session object created for the current thread (Thread which is in execution at a given instant).

Thread Local Operations…

  • set(Session ) – This method will set a given session to the sessionContext.
  • Session get() – This method returns the session from sessionContext.
  • void remove() – Removes the session from sessionContext.

Retrieving a Session…

A new user logged in and started the login thread, now the thread needs to access the session from the container.


package demo;
import java.util.Date;
public class SessionContextHolder {
public Session retrieve() {
Session session = sessionContext.get();
if (session == null) {
return create();
}
Date currentTimeStamp = new Date();
if (new Date().getTime() – session.getTimestamp().getTime() > 3000) {
sessionContext.remove();
return create();
}
return session;
}
private Session create() {
Session session = new Session();
sessionContext.set(session);
return session;
}
}

About the Code…

The login thread will call the retrieve() method and it will get the session from context using get() method. If the session is not available, a new session is created and inserted to sessionContext using the set() method. If there is a session, we check the expiry time and if it is greater than 3 secs, means it is inactive we remove it from sessionContext using remove() method.

Here we are doing everything at the same place. As you can see the session is created in the holder class which is not good. It is a good practice to let the Session class do the session creation and add it to the context. For this, we can expose the sessionContext using a public method.

Implementation of Thread Local…

It’s simply a table or map of name-value pairs and is located in the current thread instance. This means a simple thread can have multiple thread-local variables. Take a look at the source code from Thread.

/* ThreadLocal values pertaining to this thread. This map is maintained
 * by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;

When we call the set() method the following things happen,

  1. Get the current thread and load its ThreadLocalMap.
  2. If ThreadLocalMap exists, we add the value (session in our example) to it with the key as the caller thread-local instance.
  3. If ThreadLocalMap does not exist, a new one will be created for the current thread.

When we call get() method the following things happen,

  1. Get the current thread and load its ThreadLocalMap.
  2. Get the value (session in our example) using the key as the caller thread-local instance.

Demo Source Code…

The completed source code of the demo program and its output is available in my GitHub. There are two login threads they both refer to the session context for getting the session and performing operations.

Thanks for Reading

Seyed Sahil