ThreadLocal源码学习

概念:
ThreadLocal并不是一个Thread,而是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据。
ThreadLocal为解决多线程程序的并发问题提供了一种新的思路
原理:
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
源码分析:

  • Implements a thread-local storage, that is, a variable for which each thread
  • has its own value. All threads share the same {@code ThreadLocal} object,
  • but each sees a different value when accessing it, and changes made by one
  • thread do not affect the other threads. The implementation supports
*实现一个线程本地存储,每个线程的一个变量
*有它自己的价值。所有线程共享相同的ThreadLocal对象,
*但每看到一个不同的价值当访问它,和更改
*线程不会影响其他线程
public class ThreadLocal {
可以看出threadlocal是一个范型类,这标志着threadlocal可以存储所有数据
set()方法:
public void set(T value) {
Thread currentThread = Thread.currentThread(); //获取当前运行的线程
Values values = values(currentThread); //返回一个存储类
if (values == null) {
values = initializeValues(currentThread); //初始化return new Values()
}
values.put(this, value); //插入
}
首先会获取当前线程,根据当前线程获取Values存储类,再调用values存储类中的put方法,将内容存储到Values内部类的table数组的下标key.reference中。
values.put():
void put(ThreadLocal key, Object value) {
cleanUp();
// Keep track of first tombstone. That's where we want to go back // and add an entry if necessary. int firstTombstone = -1; for (int index = key.hash & mask; ; index = next(index)) { Object k = table[index]; if (k == key.reference) { // Replace existing entry. table[index + 1] = value; return; }if (k == null) { if (firstTombstone == -1) { // Fill in null slot. table[index] = key.reference; table[index + 1] = value; size++; return; }// Go back and replace first tombstone. table[firstTombstone] = key.reference; table[firstTombstone + 1] = value; tombstones--; size++; return; }// Remember first tombstone. if (firstTombstone == -1 && k == TOMBSTONE) { firstTombstone = index; } } }

把values的值传入到一个table数组的key.reference的下一个下标中
table就以key,value的形式存储了线程的本地变量,偶数位放key,基数位放value。
两个地方不太清楚
1.key.reference 是什么值
2.for (int index = key.hash & mask; ; index = next(index)) 条件是什么?
get():
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this); }

方法返回一个当前线程的当前value值,如果这个值没有初始化,那么会通过initialValue(); 返回一个null。
remove():
void remove(ThreadLocal key) { cleanUp(); for (int index = key.hash & mask; ; index = next(index)) { Object reference = table[index]; if (reference == key.reference) { // Success! table[index] = TOMBSTONE; table[index + 1] = null; tombstones++; size--; return; }if (reference == null) { // No entry found. return; } } }

内存释放,手动释放当前线程的存储的值。
ThreadLocal和线程同步机制相比有什么优势呢?
对于同步机制中来说,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。
【ThreadLocal源码学习】对于ThreadLocal来说,它为每一个线程提供一个独立的变量副本
,从而隔离了多个线 程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编 写多线程代码时,可以把不安全的变量封装进ThreadLocal,从另一个角度来解决多线程的并发访问。

    推荐阅读