ThreadLocal是什么?
ThreadLocal从字面上的理解是本地线程的意思,然而事实上它是共享变量的一份拷贝,所以称之为ThreadLocalvVariable更合适
ThreadLocal对于多线程数据共享的意义?
下面举个多线程共享一个对象的例子(理解为单例)
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();
}
}
运行结果
Thread: Thread-1, name: zhangfei, myName: zhangfei
Thread: Thread-2, name: zhangfei, myName: guanyu
Thread: Thread-0, name: zhangfei, myName: liubei
通过ThreadLocal改造Student代码,获取正确的结果
package com.test.threadLocal;
public class Student {
private String name;
private static ThreadLocal threadLocal = new ThreadLocal();
public static String getName() {
return threadLocal.get();
}
public static void setName(String name) {
threadLocal.set(name);
}
}
运行结果
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) {
//获取当前线程
Thread t = Thread.currentThread();
//ThreadLocalMap是ThreadLocal的一个静态内部类,这里从数据结构上可以把ThreadLocalMap理解成HashMap,HashMap的解析会在之后的博客中解释
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}.
*
* 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
*/
//用来设置初始化的value值,由子类决定是否重写
protected T initialValue() {
return null;
}
对ThreadLocal,ThreadLocalMap和Thread的关系的理解
简单的说每一个Thread对应的它的一个ThreadLocalMap,而ThreadLocalMap的key就是ThreadLocal,value是对应存储的值。从上述原代码中还可以得知,只要Thread没销毁,就能从ThreadLocalMap中get到你要的东西,换句话说,我们也可以将我们认为重要的信息存进去,其实Struts2中的ActionContext就是这么做的
synchronized和ThreadLocal的区别
对于多线程资源共享的问题,synchronized采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。