preface

Today’s study is ThreadLocal, which I came into contact with a year ago when I was learning the basics of JavaWeb. At that time, the first blog ThreadLocal was found on Baidu. In the comments, many developers thought that the blogger misunderstood and gave a lot of related links to correct it (but the original blogger may not be on the blog anymore, It has not been modified). I also went to study, but unfortunately there was no habit of recording at that time, and I have only scratched the surface of what I learned at that time.

Therefore, it’s important to keep track of the technology. ThreadLocal is also a common interview question and a must-know for Java developers

Of course, please forgive me if I make any mistakes, and feel free to comment in the comments

What is a ThreadLocal

Declaration: JDK 1.8 is used in this article

First, let’s take a look at the JDK documentation:


/**
 * This class provides thread-local variables.  These variables differ from
 * their normal counterparts in that each thread that accesses one (via its
 * {@code get} or {@code set} method) has its own, independently initialized
 * copy of the variable.  {@code 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).
 * 
 * <p>For example, the class below generates unique identifiers local to each
 * thread.
 * A thread's id is assigned the first time it invokes {@code ThreadId.get()}
 * and remains unchanged on subsequent calls.
 */  	
	
Copy the code

ThreadLocal provides a local variable for a thread. Each thread can use set() and get() to operate on this local variable, but it does not conflict with other threads’ local variables, achieving thread data isolation ~.

In short: The variables that are populated into a ThreadLocal belong to the current thread and are isolated from other threads.

Why learn ThreadLocal?

ThreadLocal allows us to own variables of the current thread, so what does that do?

2.1 manage the Connection

** The most typical is the management of database Connection: ** when learning JDBC, in order to facilitate the operation of a simple database Connection pool, the need for a database Connection pool reason is very simple, frequently create and close the Connection is a very expensive operation, so you need to create a database Connection pool ~

So, how to manage the database connection pool connection? We leave it to ThreadLocal to manage. Why do you leave it in charge? ThreadLocal enables the current thread to use the same Connection for all operations, ensuring transactions!

Code written when:


public class DBUtil {
    // Database connection pool
    private static BasicDataSource source;

    // Manages connections for different threads
    private static ThreadLocal<Connection> local;


    static {
        try {
            // Load the configuration file
            Properties properties = new Properties();

            // Get the read stream
            InputStream stream = DBUtil.class.getClassLoader().getResourceAsStream("Connection pool /config.properties");

            // Read data from the configuration file
            properties.load(stream);

            / / close the flow
            stream.close();

            // Initialize the connection pool
            source = new BasicDataSource();

            // Set the driver
            source.setDriverClassName(properties.getProperty("driver"));

            / / set the url
            source.setUrl(properties.getProperty("url"));

            // Set the user name
            source.setUsername(properties.getProperty("user"));

            // Set the password
            source.setPassword(properties.getProperty("pwd"));

            // Set initial number of connections
            source.setInitialSize(Integer.parseInt(properties.getProperty("initsize")));

            // Set maximum number of connections
            source.setMaxActive(Integer.parseInt(properties.getProperty("maxactive")));

            // Set the maximum waiting time
            source.setMaxWait(Integer.parseInt(properties.getProperty("maxwait")));

            // Set the minimum idle number
            source.setMinIdle(Integer.parseInt(properties.getProperty("minidle")));

            // Initialize thread local
            local = new ThreadLocal<>();


        } catch(IOException e) { e.printStackTrace(); }}public static Connection getConnection(a) throws SQLException {
        
        if(local.get()! =null) {return local.get();
        }else{
        
            // Get the Connection object
            Connection connection = source.getConnection();
    
            // Put the Connection in a ThreadLocal
            local.set(connection);
    
            // Return a Connection object
            returnconnection; }}// Close the database connection
    public static void closeConnection(a) {
        // Get the Connection object from the thread
        Connection connection = local.get();

        try {
            if(connection ! =null) {
                // Restore the connection to automatic commit
                connection.setAutoCommit(true);

                // The connection is not actually closed, but returned to the connection pool
                connection.close();

                // Since the connection has been returned to the connection pool, the Connction object stored by ThreadLocal is uselesslocal.remove(); }}catch(SQLException e) { e.printStackTrace(); }}}Copy the code

Similarly, Hibernate manages connections in the same way (using ThreadLocal, although Hibernate’s implementation is more powerful)

2.2 Avoid passing some parameters

To understand how to avoid passing some parameters, see Cookie and Session:

  • Every time I visit a page, the browser finds the Cookie from the hard drive and sends it to me.
  • Browsers are smart enough not to send cookies from other sites, but only those published by the current site

The browser acts like a ThreadLocal. It only sends cookies that exist in our current browser (local variables of the ThreadLocal). Different browsers are isolated from cookies (Chrome,Opera,IE are isolated from cookies). In IE you also have to log in again.) similarly: ThreadLocal variables are isolated from each other….

Does it avoid passing parameters? It’s actually avoided.

In the programming is the same: daily we have to deal with business may have a lot of places to use ID card, all kinds of documents, every time we have to take out very troublesome


    // When consulting, you should use your ID card, student ID card, real estate certificate and so on....
    public void consult(IdCard idCard,StudentCard studentCard,HourseCard hourseCard){}// When dealing with id card, student card, real estate certificate and so on....
    public void manage(IdCard idCard,StudentCard studentCard,HourseCard hourseCard) {}/ /...

Copy the code

If you use a ThreadLocal, the ThreadLocal is like an institution, and the ThreadLocal institution keeps track of how many credentials you have. When use need not oneself take, ask an organization to take ok.

In the consultation of the time to tell the agency: come, my ID card, house property card, student card all to him. In handling and told the agency: come, my ID card, house property card, student card all to him. .


    // When consulting, you should use your ID card, student ID card, real estate certificate and so on....
    public void consult(a){

        threadLocal.get();
    }

    // When dealing with id card, student card, real estate certificate and so on....
    public void takePlane(a) {
        threadLocal.get();
    }

Copy the code

I think it’s a lot easier than doing it yourself.

Of course, there may be other better uses of ThreadLocal, so if you know about it, leave a comment

Three, ThreadLocal implementation principle

To better understand ThreadLocal, you need to look at how it is implemented

Declaration: JDK 1.8 is used in this article

First, let’s take a look at the set() method of a ThreadLocal, since we usually use new to set objects inside


    public void set(T value) {

		// Get the current thread object
        Thread t = Thread.currentThread();
		
		// Get ThreadLocalMap here
        ThreadLocalMap map = getMap(t);

		// If the map exists, the current thread object t is stored in the map as the key and the object to be stored as the value
        if(map ! =null)
            map.set(this, value);
        else
            createMap(t, value);
    }

Copy the code

There’s a ThreadLocalMap up there, so let’s see what is this?


static class ThreadLocalMap {

        /** * The entries in this hash map extend WeakReference, using * its main ref field as the key (which is always a * ThreadLocal object). Note that null keys (i.e. entry.get() * == null) mean that the key is no longer referenced, so the * entry can be expunged from table. Such entries are referred to * as "stale entries" in the code that follows. * /
        static class Entry extends WeakReference<ThreadLocal<? >>{
            /** The value associated with this ThreadLocal. */Object value; Entry(ThreadLocal<? > k, Object v) {super(k); value = v; }}/ /... For a long
}
Copy the code

What we can see above is that ThreadLocalMap is an inner class of ThreadLocal. Use the Entry class for storage

Our values are stored on this Map, and the key is the current ThreadLocal object!

If the Map does not exist, initialize one:


    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
Copy the code

If the Map exists, get it from the Thread!


    /**
     * Get the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param  t the current thread
     * @return the map
     */
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

Copy the code

Thread maintains the ThreadLocalMap variable


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

As you can see above, ThreadLocalMap is written using inner classes in ThreadLocal, but references to objects are in Thread!

The key of a ThreadLocalMap is the LocalThread object itself, and the value is the object to be stored

With that in mind, the get() method is not difficult to understand at all:


    public T get(a) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if(map ! =null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if(e ! =null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                returnresult; }}return setInitialValue();
    }
Copy the code

3.1 Summary of ThreadLocal principles

  1. Each Thread maintains a reference to a ThreadLocalMap
  2. ThreadLocalMap is an inner class of ThreadLocal, stored in entries
  3. When you call the set() method of a ThreadLocal, you are actually setting the value to the ThreadLocalMap, with the key being the ThreadLocal object and the value being the object passed in
  4. When you call the get() method of a ThreadLocal, you actually get a value from the ThreadLocalMap, and the key is the ThreadLocal object
  5. The ThreadLocal itself does not store values; it simply acts as a key for the thread to get values from the ThreadLocalMap.

Because of this principle, ThreadLocal can achieve “data isolation”, the value of the local variable of the current thread, but not other threads

4. Avoid memory leaks

Let’s take a look at the object-relational reference graph of ThreadLocal:

The root cause of a ThreadLocal memory leak is that because ThreadLocalMap has the same lifetime as Thread, failure to manually remove the corresponding key would cause a memory leak, not a weak reference.

Remove () manually if you want to avoid memory leaks!

Five, the summary

There are tons of ThreadLocal blog posts on this topic, and a quick search of them sums up this post on the shoulders of others

Finally, keep in mind that ThreadLocal is designed to be able to have its own variables in the current thread, not to deal with concurrency or shared variables

If not enough, feel not deep enough students can refer to the following link, a lot of bloggers also carry out some expanded knowledge, I will not expand one ~

Reference blog:

  • Blog.xiaohansong.com/2016/08/06/…
  • www.cnblogs.com/zhangjk1993…
  • www.cnblogs.com/dolphin0520…
  • www.cnblogs.com/dolphin0520…
  • www.iteye.com/topic/10380…
  • www.cnblogs.com/xzwblog/p/7…
  • Blog.csdn.net/u012834750/…
  • Blog.csdn.net/winwill2012…
  • Juejin. Im/post / 684490…

If the article is wrong, welcome to correct, we communicate with each other. Used to read technical articles in wechat, want to get more Java resources, students can follow the wechat public number :Java3y