Today, one of the most critical aspects
of a concurrent application is shared data. When you create thread that
implements the Runnable interface and then start various Thread objects using
the same Runnable object, all the threads share the same attributes that are
defined inside the runnable object.
This essentially means that if you change
any attribute in a thread, all the threads will be affected by this change and
will see the modified value by first thread.
Sometimes it is desired behavior e.g.
multiple threads increasing / decreasing the same counter variable; but
sometimes you want to ensure that every thread MUST work on its own copy of
thread instance and does not affect others data.
When to use ThreadLocal?
For example, consider you are working on an
eCommerce application. You have a requirement to generate a unique transaction
id for each and every customer request this controller process and you need to
pass this transaction id to the business methods in manager/DAO classes for
logging purpose. One solution could be passing this transaction id as a
parameter to all the business methods. But this is not a good solution as the
code is redundant and unnecessary.
To solve that, here you can use ThreadLocal
variable. You can generate a transaction id in controller OR any pre-processor
interceptor; and set this transaction id in the ThreadLocal. After this,
whatever the methods, that this controller calls, they all can access this
transaction id from the threadlocal. Also note that application controller will
be servicing more that one request at a time and since each request is
processed in separate thread at framework level, the transaction id will be
unique to each thread and will be accessible from all over the thread’s
execution path.
Inside ThreadLocal Class?
The Java Concurrency API provides a clean
mechanism for thread-local variables using ThreadLocal class with a very good
performance.
public class ThreadLocal<T> extends
Object {...}
This class provides thread-local
variables. These variables differ from their normal counterparts in that each
thread that accesses one (via its get or set method) has its own, independently
initialized copy of the variable. ThreadLocal instances are typically private
static fields in classes that wish to associate state with a thread (e.g., a user
ID or Transaction ID).
This class has following methods:
· get()
: Returns the value in the current thread’s copy of this thread-local variable.
· initialValue()
: Returns the current thread’s “initial value” for this thread-local variable.
· remove()
: Removes the current thread’s value for this thread-local variable.
· set(T
value) : Sets the current thread’s copy of this thread-local variable to the
specified value.
How to use ThreadLocal?
Below example uses two thread local
variables i.e. threadId and startDate. Both have been defined as “private
static” fields as recommended. ‘threadId‘ will be used to identify the thread
which is currently running and ‘startDate‘ will be used to get the time when
thread started it’s execution. Above information will be printed in console to
verify that each thread has maintained it’s own copy of variables.
class DemoTask implements Runnable {
// Atomic integer containing the next thread ID to be assigned
private static final AtomicInteger nextId = new AtomicInteger(0);
// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return nextId.getAndIncrement();
}
};
// Returns the current thread's unique ID, assigning it if
necessary
public int getThreadId() {
return threadId.get();
}
// Returns the current thread's starting timestamp
private static final ThreadLocal<Date> startDate = new ThreadLocal<Date>() {
protected Date initialValue()
{
return new Date();
}
};
@Override
public void run() {
System.out.printf("Starting Thread: %s : %s\n", getThreadId(), startDate.get());
try {
TimeUnit.SECONDS.sleep((int) Math.rint(Math.random()
* 10));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("Thread Finished: %s : %s\n", getThreadId(), startDate.get());
}
}
Now to verify that variables essentially
are able to maintain their state irrespective of multiple initializations for
multiple threads, let’s create three instances of this task; start the threads;
and then verify the information they print in console.
Starting Thread: 0 : Wed Dec 24 15:04:40 IST 2014
Thread Finished: 0 : Wed Dec 24 15:04:40 IST 2014
Starting Thread: 1 : Wed Dec 24 15:04:42 IST 2014
Thread Finished: 1 : Wed Dec 24 15:04:42 IST 2014
Starting Thread: 2 : Wed Dec 24 15:04:44 IST 2014
Thread Finished: 2 : Wed Dec 24 15:04:44 IST 2014
In above output, sequence of printed
statement will vary every time. I have put them in sequence so that we can
clearly identify that thread local values are kept safe for each thread
instance; and never intermixed.
Most common use of thread local is when
you have some object that is not thread-safe, but you want to avoid
synchronizing access to that object using synchronized keyword/block. Instead,
give each thread its own instance of the object to work with.
A good alternative to synchronization or threadlocal
is to make the variable a local variable. Local variables are always thread
safe. The only thing which may prevent you to do this is your application
design constraints.
[Multithreading Interview Questions]
We recommend you take Big Data Hadoop class room training at eMexo Technologies in electronic city, Bangalore to learn more about Big Data Hadoop.