This is my first article on getting started
I met a ThreadLocal
Let’s start with a piece of code to get to know ThradLocal
The main program
package com.example.threadlocal_01.com.yang;
/** * static: creates a tl of ThreadLocal objects when the class is loaded and all objects are shared * thread 1: prints a Person object with set() * thread 2: To exclude the effect of thread execution speed, thread 1 sleeps for 1s and thread 2 sleeps for 2s */
public class ThreadLocalDemo01 {
static ThreadLocal<Person> tl = new ThreadLocal<>();
public static void main(String[] args) {
/ / thread
new Thread(() -> {
SleepHelper.sleep(1);
tl.set(new Person("Zhang"));
System.out.println(Thread.currentThread().getName() +":"+ tl.get());
}).start();
/ / thread 2
new Thread(() -> {
SleepHelper.sleep(2);
System.out.println(Thread.currentThread().getName() +":"+ tl.get()); }).start(); }}Copy the code
Related classes
- SleepHelper
public class SleepHelper {
public static void sleep(int seconds) {
try {
Thread.sleep(1000L * seconds);
} catch(InterruptedException e) { e.printStackTrace(); }}}Copy the code
- Person
@Data
@AllArgsConstructor
public class Person {
String name;
}
Copy the code
Before executing the code, we can predict the output based on past experience, and look at the results with the answers to reinforce our impression.
- The output
Thread-0:Person(name= name) Thread-1:null
Copy the code
The result is different from what I expected. I set the value in the shared TL object, but the second thread did not get it.
conclusion
Check data, ThreadLocal can be understood as a global variable, the current thread only applies to the current thread, so the tl in the thread a set value, thread two get less than, by definition appears to explain, but the tl must be a Shared object, which in turn and runs counter to common sense, with doubt, decided to have a look at the source.
Explore the ThreadLocal source code
The set () method
public void set(T value) {
// Get the current thread
Thread t = Thread.currentThread();
// Get a ThreadLocalMap object by passing in the current thread object
ThreadLocalMap map = getMap(t);
// If the map is not empty, use this as the key,Person as the value, and set the map. If the map is empty, create one
if(map ! =null)
map.set(this, value);
else
createMap(t, value);
}
Copy the code
This here refers to the TL object that calls the set method
getMap(t)
ThreadLocalMap getMap(Thread t) {
// Return the current thread's threadLocals
return t.threadLocals;
}
Copy the code
threadLocals
// Member variables of the Thread object
ThreadLocal.ThreadLocalMap threadLocals = null;
Copy the code
get()
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
getMap(t)
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
Copy the code
We know that any Thread object that has a member variable called threadLocals of type Map exists here, so no other Thread can get the value from its threadLocals.
Note items when using ThreadLocal
Memory leak: Memory is used up and cannot be released. Memory overflow: Memory is used up and finally, memory is not enough to overflow. A memory leak may cause a memory overflow
- ThreadLocal usage can cause memory leaks
When a thread uses a ThreadLocal, if the thread is always present, the memory occupied by the map will never be released, resulting in a memory leak. If the thread is left untreated, the map will eventually cause a serious waste of resources and eventually lead to a memory overflow. So we should manually empty the map when using ThreadLocal so that the GC can discover and reclaim the memory.
remove()
public void remove(a) {
ThreadLocalMap m = getMap(Thread.currentThread());
if(m ! =null)
m.remove(this);
}
Copy the code
ThreadLocal is used in thread pools
- A memory leak
- Data inconsistency
When we talk about thread deathless, we naturally think of thread pools. When we use ThreadLocal in a thread pool, if we don’t remove() it, there is a memory leak. We know that the feature of thread pool is to create multiple threads at a time, and the thread is not destroyed and reused. Then, the value set in map is not cleared when I use it last time, and the next time I use other methods, I will directly get the value of the last time, and the data will be confused.
extension
The Entry object in ThreadLocalMap
Weak references: When found by GC, they are reclaimed
Entry
static class Entry extends WeakReference<ThreadLocal<? >>{
/** The value associated with this ThreadLocal. */Object value; Entry(ThreadLocal<? > k, Object v) {super(k); value = v; }}Copy the code
We find that the Entry here inherits from a weak reference. Here’s an interesting thing that’s hard to say. Look at the picture
Why do we use a weak reference here? If we use a strong reference, even if the TL object is null, the key in the map still points to the ThreaLocal object, so it still causes a memory leak. Even if the ThreadLocal object is reclaimed, the key becomes null and the entire Value object is no longer accessible, so there will still be a memory leak, which is not the case with weak references.
In the last words
Finally, let’s talk about the process of writing this article. When I decided to write this topic, I also read a lot of big guy’s articles. In the process of writing, I was also very uneasy, afraid of making some stupid mistakes, and misled the friends who saw this article. Therefore, when writing, it is also very careful. In the process of writing, it will be found that a simple knowledge point is very simple to understand, but it seems not a simple thing to express it and let people understand it. On the road of learning, we still need to forge ahead. If there is any mistake, please correct the big guy!