ThreadLocal 详解

ThreadLocal,我们一般称之为线程的局部变量,或者是线程的本地变量。很多人认为他与多线程的同步机制相关,其实是错误的。ThreadLocal虽然提供了一种解决多线程环境下成员变量的问题,但是它并不是解决多线程共享变量的问题。

ThreadLocal 详解_第1张图片
Thread、ThreadLocal、ThreadLocalMap的关系

来看看其有哪些实际的地方使用到过。

public class SeqCount {
    private static ThreadLocal seqCount = new ThreadLocal(){
        // 实现initialValue()
        public Integer initialValue() {
            return 0;
        }
    };

    public int nextSeq(){
        seqCount.set(seqCount.get() + 1);
        return seqCount.get();
    }

    public static void main(String[] args){
        SeqCount seqCount = new SeqCount();

        SeqThread thread1 = new SeqThread(seqCount);
        SeqThread thread2 = new SeqThread(seqCount);
        SeqThread thread3 = new SeqThread(seqCount);
        SeqThread thread4 = new SeqThread(seqCount);

        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }

    private static class SeqThread extends Thread{
        private SeqCount seqCount;

        SeqThread(SeqCount seqCount){
            this.seqCount = seqCount;
        }

        public void run() {
            for(int i = 0 ; i < 3 ; i++){
                System.out.println(Thread.currentThread().getName() + 
                                   " seqCount :" + seqCount.nextSeq());
            }
        }
    s}
}

运行结果如下:


ThreadLocal 详解_第2张图片
运行结果
二、源码解析

ThreadLocal定义了四个方法:

  • get():返回此线程局部变量的当前线程副本中的值。
public T get( ) {
    // 获取当前线程
    Thread t = Thread.currentThread();
    // 获取当前线程的成员变量 threadLocal
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        // 从当前线程的ThreadLocalMap获取相对应的Entry
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null)
            return (T)e.value;
    }
    return setInitialValue();
}

// getMap()方法可以获取当前线程所对应的ThreadLocalMap,如下:
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}
  • set(T value):将此线程局部变量的当前线程副本中的值设置为指定值
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

/*
 ** 获取当前线程所对应的ThreadLocalMap,如果不为空,则调用ThreadLocalMap的set()方法,
 ** key就是当前ThreadLocal,如果不存在,则调用createMap()方法新建一个
 */
void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}
  • initialValue():返回此线程局部变量的当前线程的“初始值”。
protected T initialValue() {
    return null;
}

该方法定义为protected级别且返回为null,很明显是要子类实现它的,所以我们在使用ThreadLocal的时候一般都应该覆盖该方法。该方法不能显示调用,只有在第一次调用get()或者set()方法时才会被执行,并且仅执行1次。

  • remove():移除此线程局部变量当前线程的值。
public void remove() {
    ThreadLocalMap m = getMap(Thread.currentThread());
    if (m != null)
        m.remove(this);
}

该方法的目的是减少内存的占用。当然,我们不需要显示调用该方法,因为一个线程结束后,它所对应的局部变量就会被垃圾回收。

ThreadLocal的一个内部类:ThreadLocalMap,他承担了ThreadLocal的存储工作。看看ThreadLocalMap定义:

static class Entry extends WeakReference> {
        /** The value associated with this ThreadLocal. */
        Object value;
        Entry(ThreadLocal k, Object v) {
            super(k);
            value = v;
        }
}

你可能感兴趣的:(ThreadLocal 详解)