ThreadLocal是什么?
ThreadLocal從字面上的理解是本地線程的意思,然而事實(shí)上它是共享變量的一份拷貝,所以稱之為ThreadLocalvVariable更合適
ThreadLocal對(duì)于多線程數(shù)據(jù)共享的意義?
下面舉個(gè)多線程共享一個(gè)對(duì)象的例子(理解為單例)
package com.test.threadLocal;
public class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.test.threadLocal;
public class MyThread extends Thread {
private Student student;
private String name;
public MyThread(Student student,String name) {
this.student = student;
this.name = name;
}
@Override
public void run() {
this.student.setName(name);
String myName = name;
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("Thread: " + Thread.currentThread().getName()
+ ", name: " + student.getName() + ", myName: " + myName);
}
}
package com.test.threadLocal;
public class Test
{
public static void main(String[] args)
{
Student student = new Student();
MyThread thread0 = new MyThread(student, "liubei");
MyThread thread1 = new MyThread(student, "zhangfei");
MyThread thread2 = new MyThread(student, "guanyu");
thread0.start();
thread1.start();
thread2.start();
}
}
運(yùn)行結(jié)果
Thread: Thread-1, name: zhangfei, myName: zhangfei
Thread: Thread-2, name: zhangfei, myName: guanyu
Thread: Thread-0, name: zhangfei, myName: liubei
通過ThreadLocal改造Student代碼,獲取正確的結(jié)果
package com.test.threadLocal;
public class Student {
private String name;
private static ThreadLocal<String> threadLocal = new ThreadLocal<String>();
public static String getName() {
return threadLocal.get();
}
public static void setName(String name) {
threadLocal.set(name);
}
}
運(yùn)行結(jié)果
Thread: Thread-2, name: guanyu, myName: guanyu
Thread: Thread-1, name: zhangfei, myName: zhangfei
Thread: Thread-0, name: liubei, myName: liubei
ThreadLocal類中重要的方法
ThreadLocal類的set方法
/ ** Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
//獲取當(dāng)前線程
Thread t = Thread.currentThread();
//ThreadLocalMap是ThreadLocal的一個(gè)靜態(tài)內(nèi)部類,這里從數(shù)據(jù)結(jié)構(gòu)上可以把ThreadLocalMap理解成HashMap,HashMap的解析會(huì)在之后的博客中解釋
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocal類的getMap和createMap方法
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
Thread類的threadLocals變量
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal類的get方法
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
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;
return result;
}
}
return setInitialValue();
}
ThreadLocal的setInitialValue,initialValue方法
/**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
*
* @return the initial value
*/
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
/**
* Returns the current thread's "initial value" for this
* thread-local variable. This method will be invoked the first
* time a thread accesses the variable with the {@link #get}
* method, unless the thread previously invoked the {@link #set}
* method, in which case the {@code initialValue} method will not
* be invoked for the thread. Normally, this method is invoked at
* most once per thread, but it may be invoked again in case of
* subsequent invocations of {@link #remove} followed by {@link #get}.
*
* <p>This implementation simply returns {@code null}; if the
* programmer desires thread-local variables to have an initial
* value other than {@code null}, {@code ThreadLocal} must be
* subclassed, and this method overridden. Typically, an
* anonymous inner class will be used.
*
* @return the initial value for this thread-local
*/
//用來設(shè)置初始化的value值,由子類決定是否重寫
protected T initialValue() {
return null;
}
對(duì)ThreadLocal,ThreadLocalMap和Thread的關(guān)系的理解
簡單的說每一個(gè)Thread對(duì)應(yīng)的它的一個(gè)ThreadLocalMap,而ThreadLocalMap的key就是ThreadLocal,value是對(duì)應(yīng)存儲(chǔ)的值。從上述原代碼中還可以得知,只要Thread沒銷毀,就能從ThreadLocalMap中g(shù)et到你要的東西,換句話說,我們也可以將我們認(rèn)為重要的信息存進(jìn)去,其實(shí)Struts2中的ActionContext就是這么做的
synchronized和ThreadLocal的區(qū)別
對(duì)于多線程資源共享的問題,synchronized采用了“以時(shí)間換空間”的方式,而ThreadLocal采用了“以空間換時(shí)間”的方式。前者僅提供一份變量,讓不同的線程排隊(duì)訪問,而后者為每一個(gè)線程都提供了一份變量,因此可以同時(shí)訪問而互不影響。