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
- Each Thread maintains a reference to a ThreadLocalMap
- ThreadLocalMap is an inner class of ThreadLocal, stored in entries
- 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
- When you call the get() method of a ThreadLocal, you actually get a value from the ThreadLocalMap, and the key is the ThreadLocal object
- 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