虽然这个不是标准的数据结构,但是在java中还是挺重要的结构类。所以需要好好了解一下
该类的使用非常简单,大概就下面的两个操作。
static final ThreadLocal<T> sThreadLocal = new ThreadLocal<T>();
sThreadLocal.set()
sThreadLocal.get()
sThreadLocal.remove()
ThreadLocal存在一个静态内部类ThreadLocalMap。当调用set的时候,首先获取当前线程对象t。然后线程t中存在一个成员变量threadLocals (指向ThreadLocal的静态内部类ThreadLocalMap),默认为null。 //如果存在ThreadLocalMap就直接set,没有则创建ThreadLocalMap并set。 然后将ThreadLocal对象作为key,用户的值作为value值。放入map中。
其实具体是采用ThreadLocal的threadLocalHashCode属性作为key。该属性是被final修饰的int不可变属性。所以可以唯一确定一个ThreadLocal对象。
但是如何保证两个同时实例化的ThreadLocal对象有不同的threadLocalHashCode属性:在ThreadLocal类中,还包含了一个static修饰的AtomicInteger([??t?m?k]提供原子操作的Integer类)成员变量(即类变量)和一个static final修饰的常量(作为两个相邻nextHashCode的差值)。由于nextHashCode是类变量,所以每一次调用ThreadLocal类都可以保证nextHashCode被更新到新的值,并且下一次调用ThreadLocal类这个被更新的值仍然可用,同时AtomicInteger保证了nextHashCode自增的原子性。
总的来说其原理主要是通过为每个Thread 维护一个属于自己的map。然后通过不同的ThreadLocal对象作为key来存取不同的value值。也就是说再多线程环境中,对于同一个ThreadLocal对象,当处于不同的线程中时,对应的value值是不一样的。因为线程不一样->map不一样。
package ztext;
/**
* @author xgj
*/
public class MyTest {
ThreadLocal<Long> longLocal = new ThreadLocal<>();
ThreadLocal<String> stringLocal = new ThreadLocal<>();
Long along = Long.valueOf(1000);
public void set() {
along+=100;
longLocal.set(along);
stringLocal.set(Thread.currentThread().getName());
}
public long getLong() {
return longLocal.get();
}
public String getString() {
return stringLocal.get();
}
public static void main(String[] args) throws InterruptedException {
final MyTest test = new MyTest();
test.set();
System.out.println(test.getLong());
System.out.println(test.getString());
Thread thread1 = new Thread(() -> {
test.set();
System.out.println(test.getLong());
System.out.println(test.getString());
});
Thread thread2 = new Thread(() -> {
test.set();
System.out.println(test.getLong());
System.out.println(test.getString());
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
}
的运行结果如下:
也就是说对于共有变量Long,并没有起到隔离作用
如果改为:
package ztext;
/**
* @author xgj
*/
public class MyTest {
ThreadLocal<Long> longLocal = new ThreadLocal<>();
ThreadLocal<String> stringLocal = new ThreadLocal<>();
Long along = Long.valueOf(1000);
public void set() {
Long blong = along+100;
longLocal.set(blong);
stringLocal.set(Thread.currentThread().getName());
}
public long getLong() {
return longLocal.get();
}
public String getString() {
return stringLocal.get();
}
public static void main(String[] args) throws InterruptedException {
final MyTest test = new MyTest();
test.set();
System.out.println(test.getLong());
System.out.println(test.getString());
Thread thread1 = new Thread(() -> {
test.set();
System.out.println(test.getLong());
System.out.println(test.getString());
});
Thread thread2 = new Thread(() -> {
test.set();
System.out.println(test.getLong());
System.out.println(test.getString());
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
}
结果:
初始容量16,负载因子2/3,解决冲突的方法是再hash法,
原文:https://www.cnblogs.com/jiezao/p/13678520.html