DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Why "Polyglot Programming" or "Do It Yourself Programming Languages" or "Language Oriented Programming" sucks?
  • Cookies Revisited: A Networking Solution for Third-Party Cookies
  • Using Event-Driven Ansible to Monitor Your Web Application
  • The Blue Elephant in the Room: Why PHP Should Not Be Ignored Now or Ever

Trending

  • The End of “Good Enough Agile”
  • How Kubernetes Cluster Sizing Affects Performance and Cost Efficiency in Cloud Deployments
  • AI Speaks for the World... But Whose Humanity Does It Learn From?
  • Orchestrating Microservices with Dapr: A Unified Approach

Understanding the concept behind ThreadLocal

By 
Cristian Chiovari user avatar
Cristian Chiovari
·
May. 22, 13 · Interview
Likes (2)
Comment
Save
Tweet
Share
28.5K Views

Join the DZone community and get the full member experience.

Join For Free

intro

i was aware of thread local but never had the occasion to really use it until recently. so i started digging a little bit on the subject because i needed an easy way of  propagating some user information via the different layers of my web application without changing the signature of each method called.

small prerequisite info

a thread is an individual process that has its own call stack. in java, there is one thread per call stack or one call stack per thread. even if you don’t create any new threads in your program, threads are there running without your knowledge.best example is whenyou just start  a simple java program via main method,then you do not implicitly call new thread().start(),  but the jvm creates a main thread for you in order to run the main method.

the main thread is quite special because it is the thread from which all the other thread will spawn and when this thread is finished, the application ends it’s lifecycle.

in a web application server normally there is  a pool of of threads ,because a thread is class quite heavyweight to create.all jee servers (weblogic,glassfish,jboss etc) have a self tuning thread pool, meaning that the thread pool increase and decrease when is needed so there is not thread created on each request, and existing ones are reused.

understanding thread local

in order to understand better thread local i will show very simplistic implementation of one custom thread local.

package ccs.progest.javacodesamples.threadlocal.ex1;
 
import java.util.hashmap;
import java.util.map;
 
public class customthreadlocal {
 
    private static map threadmap = new hashmap();
 
    public static void add(object object) {
        threadmap.put(thread.currentthread(), object);
    }
 
    public static void remove(object object) {
        threadmap.remove(thread.currentthread());
    }
 
    public static object get() {
        return threadmap.get(thread.currentthread());
    }
 
}

so you can call anytime in your application the add method on customthreadlocal and what it will do is to put in a map the current thread as key and as value the object you want to associate with this thread. this object might be an object that you want to have access to from anywhere within the current executed thread, or it might be an expensive object you want to keep associated with the thread and reuse as many times you want.
you define a class threadcontext where you  have all information you want to propagate within the thread.

package ccs.progest.javacodesamples.threadlocal.ex1;
 
public class threadcontext {
 
    private string userid;
 
    private long transactionid;
 
    public string getuserid() {
        return userid;
    }
 
    public void setuserid(string userid) {
        this.userid = userid;
    }
 
    public long gettransactionid() {
        return transactionid;
    }
 
    public void settransactionid(long transactionid) {
        this.transactionid = transactionid;
    }
 
    public string tostring() {
        return "userid:" + userid + ",transactionid:" + transactionid;
    }
 
}

now is the time to use the threadcontext.
i will start two threads and in each thread i will add a new threadcontext instance that will hold information i want to propagate for each thread.

package ccs.progest.javacodesamples.threadlocal.ex1;
 
public class threadlocalmainsampleex1 {
 
    public static void main(string[] args) {
        new thread(new runnable() {
            public void run() {
                threadcontext threadcontext = new threadcontext();
                threadcontext.settransactionid(1l);
                threadcontext.setuserid("user 1");
                customthreadlocal.add(threadcontext);
                //here we call a method where the thread context is not passed as parameter
                printthreadcontextvalues.printthreadcontextvalues();
            }
        }).start();
        new thread(new runnable() {
            public void run() {
                threadcontext threadcontext = new threadcontext();
                threadcontext.settransactionid(2l);
                threadcontext.setuserid("user 2");
                customthreadlocal.add(threadcontext);
                //here we call a method where the thread context is not passed as parameter
                printthreadcontextvalues.printthreadcontextvalues();
            }
        }).start();
    }
}

notice:
customthreadlocal.add(threadcontext) is the line of code where the current thread is associated with the threadcontext instance
as you will see executing this code the result will be:

userid:user 1,transactionid:1
userid:user 2,transactionid:2

how this is possible because we did not passed as parameter threadcontext ,userid or trasactionid to printthreadcontextvalues ?

package ccs.progest.javacodesamples.threadlocal.ex1;
 
public class printthreadcontextvalues {
    public static void printthreadcontextvalues(){
        system.out.println(customthreadlocal.get());
    }
}

simple enough :)
when customthreadlocal.get() is called from the internal map of customthreadlocal it is retrived the object associated with the current thread.
now let’s see the samples when  is used a real threadlocal class. (the above customthreadlocal class is just to understand the principles behind threadlocal class which is very fast and uses memory in an optimal way)

package ccs.progest.javacodesamples.threadlocal.ex2;
 
public class threadcontext {
 
    private string userid;
    private long transactionid;
 
    private static threadlocal threadlocal = new threadlocal(){
        @override
        protected threadcontext initialvalue() {
            return new threadcontext();
        }
 
    };
    public static threadcontext get() {
        return threadlocal.get();
    }
    public string getuserid() {
        return userid;
    }
    public void setuserid(string userid) {
        this.userid = userid;
    }
    public long gettransactionid() {
        return transactionid;
    }
    public void settransactionid(long transactionid) {
        this.transactionid = transactionid;
    }
 
    public string tostring() {
        return "userid:" + userid + ",transactionid:" + transactionid;
    }
}

as javadoc describes : threadlocal instances are typically private static fields in classes that wish to associate state with a thread

package ccs.progest.javacodesamples.threadlocal.ex2;
 
public class threadlocalmainsampleex2 {
 
    public static void main(string[] args) {
        new thread(new runnable() {
            public void run() {
                threadcontext threadcontext = threadcontext.get();
                threadcontext.settransactionid(1l);
                threadcontext.setuserid("user 1");
                //here we call a method where the thread context is not passed as parameter
                printthreadcontextvalues.printthreadcontextvalues();
            }
        }).start();
        new thread(new runnable() {
            public void run() {
                threadcontext threadcontext = threadcontext.get();
                threadcontext.settransactionid(2l);
                threadcontext.setuserid("user 2");
                //here we call a method where the thread context is not passed as parameter
                printthreadcontextvalues.printthreadcontextvalues();
            }
        }).start();
    }
}

when get is called , a new threadcontext instance is associated with the current thread,then the desired values are set the threadcontext instance.
as you see the result is the same as for the first set of samples.

userid:user 1,transactionid:1
userid:user 2,transactionid:2

(it might be the reverse order ,so don’t worry if you see ‘user 2′ first)

package ccs.progest.javacodesamples.threadlocal.ex2;
 
public class printthreadcontextvalues {
    public static void printthreadcontextvalues(){
        system.out.println(threadcontext.get());
    }
}

another very usefull usage of threadlocal is the situation when you have a non threadsafe instance of an quite expensive object.most poular sample i found was with simpledateformat (but soon i’ll come with another example when webservices ports will be used)

package ccs.progest.javacodesamples.threadlocal.ex4;
 
import java.text.simpledateformat;
import java.util.date;
 
public class threadlocaldateformat {
    // simpledateformat is not thread-safe, so each thread will have one
    private static final threadlocal formatter = new threadlocal() {
        @override
        protected simpledateformat initialvalue() {
            return new simpledateformat("mm/dd/yyyy");
        }
    };
    public string formatit(date date) {
        return formatter.get().format(date);
    }
}

conclusion:

there are many uses for thread locals. here i describe only two: (i think the most used ones)

  • genuine per-thread context, such as user id or transaction id.
  • per-thread instances for performance.
Web application Concept (generic programming)

Published at DZone with permission of Cristian Chiovari, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Why "Polyglot Programming" or "Do It Yourself Programming Languages" or "Language Oriented Programming" sucks?
  • Cookies Revisited: A Networking Solution for Third-Party Cookies
  • Using Event-Driven Ansible to Monitor Your Web Application
  • The Blue Elephant in the Room: Why PHP Should Not Be Ignored Now or Ever

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!