The threadlocal differs from the thread member variable, threadlocal This class provides a thread-local variable. This local variable is not the same as the general member variable, threadlocal variables are used by multiple threads, each thread can only get a copy of the variable, which is described in the Java API, through the Reading API source code, found not a copy, what concept of replica? A clone? Or something else, too vague.
To be exact, the registry (map<thread,t>) of the threadlocal type of variable has changed, but the threadlocal type of the variable itself is indeed one, which is the essence!
Here's an example:
One, standard example
Define the Mythreadlocal class, create one of its object TLT, respectively, to four threads, the result of four threads TLT variable does not appear a common phenomenon, the second is the use of each, which means that four threads use a copy of the TLT (clones).
/**
* uses the Threadlocal class
/Public
class Mythreadlocal {
//defines a threadlocal variable to hold int or integer data
Private threadlocal<integer> TL = new threadlocal<integer> () {
@Override
protected Integer InitialValue () {return
0;
}
};
Public Integer Getnextnum () {
///The TL value is fetched after 1, and the value of the set T1 is updated
tl.set (tl.get () + 1);
return Tl.get ();
}
/**
* Test thread
/public class Testthread extends thread {
private mythreadlocal TLT = new mythreadlocal ();
public Testthread (mythreadlocal tlt) {
this.tlt = TLT;
}
@Override public
Void Run () {A for
(int i = 0; i < 3; i++) {
System.out.println (thread.currentthread) Name () + "\ T" + tlt.getnextnum ());}}
/**
* threadlocal test
/public class Test {public
static void Main (string[] args) {
Mythreadlocal TLT = new mythreadlocal ();
Thread T1 = new Testthread (TLT);
Thread t2 = new Testthread (TLT);
Thread t3 = new Testthread (TLT);
Thread T4 = new Testthread (TLT);
T1.start ();
T2.start ();
T3.start ();
T4.start ();
}
As you can see, three threads are independently numbered and do not affect each other:
Thread-0 1
Thread-1 1
Thread-0 2
Thread-1 2
Thread-0 3
Thread-1 3
Thread-2 1
Thread-3 1
Thread-2 2
Thread-3 2
Thread-2 3
Thread-3 3
Process finished with exit code 0
The Tlt object is a, nonsense TL object is also one, because the combinatorial relationship is one-to-one. However, the map within the TL object will create many integer objects as the threads increase. just integers and int are already universal. So the object attribute of the integer is not felt.
second, do not threadlocal
If you don't need to threadlocal, just redefine the Mythreadlocal class to:
/**
* uses the Threadlocal class *
/public class Mythreadlocal {
private Integer t1 = 0;
Public Integer Getnextnum () {return
t1=t1+1;
} defines a ThreadLocal variable that is used to hold int or Integer data
// private threadlocal<integer> tl = new ThreadLocal <Integer> () {
// @Override
// protected Integer InitialValue () {
//return 0;
// }
// };
//Public Integer Getnextnum () {/////
Take the value of TL to add 1 and update set T1 value
// Tl.set (Tl.get () + 1) ;
return tl.get ();
// }
}
Then run the test:
Thread-2 1
Thread-2 2
Thread-1 4
Thread-1 6
Thread-3 3
Thread-3 9
Thread-3
Thread-1 8
Thread-0 7
Thread-0
Thread-0
Thread-2 5
Process finished with exit code 0
From here, four threads share the TLT variable, and each thread modifies the TLT property directly.
Three, implement a threadlocal yourself
Package com.lavasoft.test2;
Import java.util.Collections;
Import Java.util.HashMap;
Import Java.util.Map; /** * uses the Threadlocal class/public class Mythreadlocal {//defines a threadlocal variable to hold int or integer data private com.la
vasoft.test2.threadlocal<integer> tl = new com.lavasoft.test2.threadlocal<integer> () {@Override
Protected Integer InitialValue () {return 0;
}
};
Public Integer Getnextnum () {///The TL value is fetched after 1, and the value of the set T1 is updated Tl.set (Tl.get () + 1);
return Tl.get (); } class Threadlocal<t> {Private Map<thread, t> Map = Collections.synchronizedmap (New hashmap<thr
EAD, t> ());
Public ThreadLocal () {} protected T InitialValue () {return null;
Public T get () {Thread t = thread.currentthread ();
T obj = map.get (t);
if (obj = = null &&!map.containskey (t)) {obj = InitialValue (); Map.put (t, obj);
return obj;
public void Set (T value) {map.put (Thread.CurrentThread (), value);
public void Remove () {Map.Remove (Thread.CurrentThread ());
}
}
To run the test:
Thread-0 1
Thread-0 2
Thread-0 3
Thread-2 1
Thread-2 2
Thread-3 1
Thread-2 3
Thread-3 2
Thread-1 1
Thread-3 3
Thread-1 2
Thread-1 3
Process finished with exit code 0
Surprisingly, this cottage version of the threadlocal also run very well, to achieve the JAVAAPI in the Threadlocal function.
Seeing the essence through phenomena
In fact, from a procedural point of view, the TLT variable is indeed a, no doubt. But why do the numbers printed out do not affect each other?
Is it because the integer is used? -----not.
The reason is: protected T initialvalue () and get (), because each thread is created when the map is not present when it is called. When it is invoked, a new variable is created with the type T. Each time a new, of course, each with a separate influence.
To see the essence, replace the integer and rewrite some of the classes:
Package com.lavasoft.test2;
Import java.util.Collections;
Import Java.util.HashMap;
Import Java.util.Map; /** * uses the Threadlocal class/public class Mythreadlocal {//defines a threadlocal variable to hold int or integer data//Private threadlocal<bean> tl = new threadlocal<bean> () {private com.lavasoft.test2.threadlocal<bean> TL =
New Com.lavasoft.test2.threadlocal<bean> () {@Override protected Bean InitialValue () {
return new Bean ();
}
};
@Override public String toString () {return "mythreadlocal{" + "tl=" + TL +
'}';
Public Beans Getbean () {return tl.get (); } class Threadlocal<t> {Private Map<thread, t> Map = Collections.synchronizedmap (New hashmap<th
Read, t> ());
Public ThreadLocal () {} protected T InitialValue () {return null; Public T get () {Thread T = Thread.CurrentThread ();
T obj = map.get (t);
if (obj = = null &&!map.containskey (t)) {obj = InitialValue ();
Map.put (t, obj);
return obj;
public void Set (T value) {map.put (Thread.CurrentThread (), value);
public void Remove () {Map.Remove (Thread.CurrentThread ());
}
}
Package com.lavasoft.test2;
/**
* Test Bean
*
/public class Bean {
private String id = "0";
Private String name = "None";
Public beans () {
} public
bean (string ID, string name) {
this.id = ID;
this.name = name;
Public String GetId () {return
ID;
}
public void SetId (String id) {
this.id = ID;
}
Public String GetName () {return
name;
}
public void SetName (String name) {
this.name = name;
}
Public String Showinfo () {return
"bean{" +
"id=" + ID + ' \ ' +
", name= '" + name + ' \ ' +
'} ';
}
}
Package com.lavasoft.test2;
/**
* Test thread
/public class Testthread extends thread {
private mythreadlocal TLT = new mythreadlocal ();
public Testthread (mythreadlocal tlt) {
this.tlt = TLT;
}
@Override public
Void Run () {
System.out.println (">>>>>:" + TLT);
for (int i = 0; i < 3 i++) {
System.out.println (Thread.CurrentThread (). GetName () + "T" +tlt.getbean () + "T" +tlt.g Etbean (). Showinfo ());}}}
Then run the test:
>>>>>:MYTHREADLOCAL{TL=COM.LAVASOFT.TEST2.MYTHREADLOCAL$1@1DE3F2D} >>>>>: MYTHREADLOCAL{TL=COM.LAVASOFT.TEST2.MYTHREADLOCAL$1@1DE3F2D} >>>>>:mythreadlocal{tl= COM.LAVASOFT.TEST2.MYTHREADLOCAL$1@1DE3F2D} >>>>>:mythreadlocal{tl=
COM.LAVASOFT.TEST2.MYTHREADLOCAL$1@1DE3F2D} Thread-1 com.lavasoft.test2.bean@291aff bean{id= ' 0 ', name= ' none '} Thread-2 com.lavasoft.test2.bean@fe64b9 bean{id= ' 0 ', name= ' none '} Thread-3 com.lavasoft.test2.bean@186db54 ' 0 ', name= ' none '} Thread-2 com.lavasoft.test2.bean@fe64b9 bean{id= ' 0 ', name= ' none '} Thread-2 com.lavasoft.test2.bean@ Fe64b9 bean{id= ' 0 ', name= ' none '} Thread-0 com.lavasoft.test2.bean@291aff bean{id= ' 0 ', name= ' none '} Thread-3 com.lavasoft.test2.bean@186db54 bean{id= ' 0 ', name= ' none '} Thread-3 com.lavasoft.test2.bean@186db54 Bean{id= ' 0 ', name = ' None '} Thread-1 com.lavasoft.test2.bean@291aff bean{id= ' 0 ', name= ' none '} Thread-0 Com.lavasoft.test2.bean@291aff Bean{id= ' 0 ', name= ' noNe '} Thread-0 com.lavasoft.test2.bean@291aff bean{id= ' 0 ', name= ' none '} Thread-1 Com.lavasoft.test2.bean@291aff
Id= ' 0 ', name= ' None '} Process finished with exit code 0
It is clear from the print result that the Tlt object of the mythreadlocal is indeed a, the TL object of the threadlocal in the Tlt object is also one, but when it will be t1t to each thread, The thread will re-create the Bean object and add it to the threadlocal map to use.
Some misunderstandings about threadlocal:
One , threadlocal is an implementation of Java threads
Threadlocal is really about Java threading, but it's not an implementation of Java threads, it's just used to maintain local variables. For each thread, provide its own version of the variant, primarily to avoid threading conflicts, and each thread maintains its own version. Independent of each other, the modification will not affect the other.
Second, threadlocal is relative to each session of
Threadlocal, as the name suggests, is for threads. On Java Web Programming, each user has its own session identifier from the beginning to the session. But threadlocal is not on the conversation floor. In fact, Threadlocal is independent of the user session. It is a server-side behavior that, when the server generates a new thread, maintains its own threadlocal.
For this misunderstanding, the individual believes that the developer should be locally based on the results of some application server tests. As we all know, the general application server maintains a set of thread pools, which means that for each visit, it is not necessarily a new thread. Instead, you have a thread caching pool. For access, first find the existing thread from the cache pool, and if it is used up, it will be reborn into a new thread.
So, because the developers themselves in the test, usually only his own testing, so that the server's burden is very small, so that each visit may be shared with the same thread, resulting in the misunderstanding: each session has a threadlocal
Third, threadlocal is relative to each thread, the user each visit will have a new threadlocal
Theoretically speaking, threadlocal is indeed relative to each thread, each thread will have its own threadlocal. But as mentioned above, a common application server maintains a set of thread pools. Therefore, access by different users may receive the same thread. Therefore, when doing based on theadlocal, care should be taken to avoid the caching of threadlocal variables, causing other threads to access this thread variable
Four, for each user access, threadlocal can be used more
It can be said that threadlocal is a double-edged sword, with the words can play a very good effect. However, if the threadlocal is not well used, it will be the same as the global variable. Code cannot be reused and cannot be tested independently. Because, some classes that could have been reused are now dependent on the threadlocal variable. These classes become unusable if they are not threadlocal on other occasions. Personally feel that Threadlocal used very well in several application occasions, it is worth reference
1, store the current session User: Quake want Jert
2, store Some context variables, such as WebWork's Actioncontext
3, storage session, such as spring Hibernate ORM Session