Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Java 9 Concurrency Cookbook, Second Edition

You're reading from   Java 9 Concurrency Cookbook, Second Edition Build highly scalable, robust, and concurrent applications

Arrow left icon
Product type Paperback
Published in Apr 2017
Publisher Packt
ISBN-13 9781787124417
Length 594 pages
Edition 2nd Edition
Languages
Concepts
Arrow right icon
Author (1):
Arrow left icon
Javier Fernández González Javier Fernández González
Author Profile Icon Javier Fernández González
Javier Fernández González
Arrow right icon
View More author details
Toc

Table of Contents (12) Chapters Close

Preface 1. Thread Management 2. Basic Thread Synchronization FREE CHAPTER 3. Thread Synchronization Utilities 4. Thread Executors 5. Fork/Join Framework 6. Parallel and Reactive Streams 7. Concurrent Collections 8. Customizing Concurrency Classes 9. Testing Concurrent Applications 10. Additional Information 11. Concurrent Programming Design

Using thread local variables

One of the most critical aspects of a concurrent application is shared data. This has special importance in objects that extend the Thread class or implement the Runnable interface and in objects that are shared between two or more threads.

If you create an object of a class that implements the Runnable interface and then start various thread objects using the same Runnable object, all the threads would share the same attributes. This means that if you change an attribute in a thread, all the threads will be affected by this change.

Sometimes, you will be interested in having an attribute that won't be shared among all the threads that run the same object. The Java Concurrency API provides a clean mechanism called thread-local variables with very good performance. They have some disadvantages as well. They retain their value while the thread is alive. This can be problematic in situations where threads are reused.

In this recipe, we will develop two programs: one that would expose the problem in the first paragraph and another that would solve this problem using the thread-local variables mechanism.

Getting ready

The example for this recipe has been implemented using the Eclipse IDE. If you use Eclipse or a different IDE, such as NetBeans, open it and create a new Java project.

How to do it...

Follow these steps to implement the example:

  1. First, implement a program that has the problem exposed previously. Create a class called UnsafeTask and specify that it implements the Runnable interface. Declare a private java.util.Date attribute:
        public class UnsafeTask implements Runnable{ 
private Date startDate;
  1. Implement the run() method of the UnsafeTask object. This method will initialize the startDate attribute, write its value to the console, sleep for a random period of time, and again write the value of the startDate attribute:
        @Override 
public void run() {
startDate=new Date();
System.out.printf("Starting Thread: %s : %s\n",
Thread.currentThread().getId(),startDate);
try {
TimeUnit.SECONDS.sleep( (int)Math.rint(Math.random()*10));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("Thread Finished: %s : %s\n",
Thread.currentThread().getId(),startDate);
}
  1. Now, implement the main class of this problematic application. Create a class called Main with a main() method. This method will create an object of the UnsafeTask class and start 10 threads using this object, sleeping for 2 seconds between each thread:
        public class Main { 
public static void main(String[] args) {
UnsafeTask task=new UnsafeTask();
for (int i=0; i<10; i++){
Thread thread=new Thread(task);
thread.start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
  1. In the following screenshot, you can see the results of this program's execution. Each thread has a different start time, but when they finish, there is a change in the value of the attribute. So they are writing a bad value. For example, check out the thread with the ID 13:
  1. As mentioned earlier, we are going to use the thread-local variables mechanism to solve this problem.
  2. Create a class called SafeTask and specify that it implements the Runnable interface:
        public class SafeTask implements Runnable {
  1. Declare an object of the ThreadLocal<Date> class. This object will have an implicit implementation that would include the initialValue() method. This method will return the actual date:
           private static ThreadLocal<Date> startDate=new
ThreadLocal<Date>(){
protected Date initialValue(){
return new Date();
}
};
  1. Implement the run() method. It has the same functionality as the run() method of UnsafeTask class, but it changes the way it accesses the startDate attribute. Now we will use the get() method of the startDate object:
        @Override 
public void run() {
System.out.printf("Starting Thread: %s : %s\n",
Thread.currentThread().getId(),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",
Thread.currentThread().getId(),startDate.get());
}
  1. The Main class of this example is the same as the unsafe example. The only difference is that it changes the name of the Runnable class.
  2. Run the example and analyze the difference.

How it works...

In the following screenshot, you can see the results of the execution of the safe sample. The ten Thread objects have their own value of the startDate attribute:

The thread-local variables mechanism stores a value of an attribute for each thread that uses one of these variables. You can read the value using the get() method and change the value using the set() method. The first time you access the value of a thread-local variable, if it has no value for the thread object that it is calling, the thread-local variable will call the initialValue() method to assign a value for that thread and return the initial value.

There's more...

The thread-local class also provides the remove() method that deletes the value stored in a thread-local variable for the thread that it's calling.

The Java Concurrency API includes the InheritableThreadLocal class that provides inheritance of values for threads created from a thread. If thread A has a value in a thread-local variable and it creates another thread B, then thread B will have the same value as thread A in the thread-local variable. You can override the childValue() method that is called to initialize the value of the child thread in the thread-local variable. It receives the value of the parent thread as a parameter in the thread-local variable.


lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime