每一个线程Thread都是持有一个map,叫ThreadLocalMap,而ThreadLocalMap是threadlocal类的静态内部类,所以写成ThreadLocal.ThreadLocalMap
Thread源码,起初这个map是空的:
ThreadLocal.ThreadLocalMap threadLocals = null;
当我们使用threadlocal的set方法时,
在开始时线程还没有这个map,map==null,那么会给当前线程new一个threadlocalmap。
ThreadLocal源码
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
那么第二次在使用set方法时,map就不为空了。可以使用thread的threadlocalmap了。
这个threadlocalmap的键是threadlocal对象引用,值是不同threadlocal对象 对应 的值。值可以是任意类型,因为使用了泛型
可以理解每个线程拥有一个threadlocalmap,有且只有一个,且跟其他线程独立。
这个map可以有多个键,键都是不同threadlocal对象,值是不同threadlocal对象 对应 的值。
举例:你建了两个threadlocal对象。
ThreadLocal a = new ThreadLocal();
ThreadLocal b = new ThreadLocal();
a.set("hello");
b.set("world");
那么线程甲中threadlocalMap就会有两个key,key a 对应 hello,key b 对应 world
线程乙中的threadlocalMap就会有两个key,key a 对应 hello,key b 对应 world
甲和乙线程的threadlocalmap是各自拥有的
详细例子:
class Student {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class TestThreadLocal implements Runnable {
ThreadLocal studentLocal = new ThreadLocal();
public static void main(String[] args) {
TestThreadLocal t = new TestThreadLocal();
new Thread(t, "t1").start();
new Thread(t, "t2").start();
}
@Override
public void run() {
accessStudent();
}
private void accessStudent() {
Student s = getStudent();
Random random = new Random();
int age = random.nextInt(100);
System.out.println("current thread set age " + Thread.currentThread().getName()
+ ":" + age);
s.setAge(age);
System.out.println("current thread first get age "
+ Thread.currentThread().getName() + ":" + s.getAge());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("current thread second get age "
+ Thread.currentThread().getName() + ":" + s.getAge());
}
public Student getStudent() {
Student s = (Student) studentLocal.get();
if (s == null) {
s = new Student();
studentLocal.set(s);
}
return s;
}
}
current thread set age t1:5
current thread set age t2:67
current thread first get age t2:67
current thread first get age t1:5
current thread second get age t2:67
current thread second get age t1:5
总结:
ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了线程保持对象的方法和避免参数传递的方便的对象访问方式
ThreadLocal的应用场合,最适合的是按线程多实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。
网上好多文章理解有误,因为每个线程拥有独立的变量,所以并不是解决共享变量同步问题!!!!!