ThreadLocal 模式是解决并发数据共享的一个典型的方案,spring,struts等经典框架都有用到ThreadLocal 的场景。
在学习实验中写了下面一个例子:
package a;
public class TestLocal {
public static ThreadLocal<User> threadLocal = new ThreadLocal<User>();
public static void set(User u) {
threadLocal.set(u);
}
public static User get() {
return threadLocal.get();
}
public static void main(String[] args) {
final User u = new User();
TestLocal.set(u);
for (int i = 0; i < 20; i++) {
new Thread(new Runnable() {
public void run() {
System.out.println("current thread name :" +Thread.currentThread().getName()+" localuser :" + TestLocal.get());}
}).start(); }
}
}
打印结果:
current thread name :Thread-1 localuser :null
current thread name :Thread-3 localuser :null
current thread name :Thread-0 localuser :null
current thread name :Thread-4 localuser :null
current thread name :Thread-7 localuser :null
current thread name :Thread-2 localuser :null
current thread name :Thread-18 localuser :null
current thread name :Thread-11 localuser :null
current thread name :Thread-6 localuser :null
current thread name :Thread-8 localuser :null
current thread name :Thread-10 localuser :null
current thread name :Thread-12 localuser :null
current thread name :Thread-14 localuser :null
current thread name :Thread-16 localuser :null
current thread name :Thread-5 localuser :null
current thread name :Thread-9 localuser :null
current thread name :Thread-13 localuser :null
current thread name :Thread-15 localuser :null
current thread name :Thread-19 localuser :null
current thread name :Thread-17 localuser :null
由于初始ThreadLocal,对你理解不太深入,刚开始有点迷惑,追其
(ThreadLocal)在set和get时源码:
/**
* 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 map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
/**
* 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)
return (T)e.value;
}
return setInitialValue();
}
显然,结果跟源码是一致的。在set方法中,程序先获得了当前线程实例 (Thread t = Thread.currentThread()),根据实例获得(ThreadLocalMap map = getMap(t))ThreadLocalMap,如果不存在就根据当前线程创建,存在则直接将变量值以当前ThreadLocal实例为key保存起来,这样value就与当前线程绑定了,这也正是ThreadLocal在处理并发共享时的精髓所在。
再回到上面的例子,本人现在主线程将user通过set方法放进了ThreadLocal上,其实这是将user绑定到了主程序,接着到新建的其他子线程里边通过get方法去哪,显然会是得到null的,因为这个时候的get方法是针对当前子线程了。
针对上面的理解,再一次写了个例子:
package a;
public class TestLocal {
public static ThreadLocal<User> threadLocal = new ThreadLocal<User>();
public static void set(User u) {
threadLocal.set(u);
}
public static User get() {
return threadLocal.get();
}
public static void main(String[] args) {
final User u = new User();
for (int i = 0; i < 20; i++) {
new Thread(new Runnable() {
public void run() {
TestLocal.set(u);
System.out.println("current thread name :" +Thread.currentThread().getName()+" localuser :" + TestLocal.get());
}
}).start();
}
}
}
控制台打印结果显示:
current thread name :Thread-0 localuser :a.User@13c5982
current thread name :Thread-1 localuser :a.User@13c5982
current thread name :Thread-3 localuser :a.User@13c5982
current thread name :Thread-5 localuser :a.User@13c5982
current thread name :Thread-2 localuser :a.User@13c5982
current thread name :Thread-4 localuser :a.User@13c5982
current thread name :Thread-6 localuser :a.User@13c5982
current thread name :Thread-9 localuser :a.User@13c5982
current thread name :Thread-7 localuser :a.User@13c5982
current thread name :Thread-11 localuser :a.User@13c5982
current thread name :Thread-13 localuser :a.User@13c5982
current thread name :Thread-17 localuser :a.User@13c5982
current thread name :Thread-19 localuser :a.User@13c5982
current thread name :Thread-14 localuser :a.User@13c5982
current thread name :Thread-16 localuser :a.User@13c5982
current thread name :Thread-10 localuser :a.User@13c5982
current thread name :Thread-15 localuser :a.User@13c5982
current thread name :Thread-12 localuser :a.User@13c5982
current thread name :Thread-18 localuser :a.User@13c5982
current thread name :Thread-8 localuser :a.User@13c5982
此时确实得到了期望的结果。