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源码学习)