Java基础知识整理6:ThreadLocal

JDK描述

public class ThreadLocal
extends Object

该类提供了线程局部 (thread-local)变量。这些变量不同于普通变量,每个线程都有自己的局部拷贝,独立于变量的初始副本。ThreadLocal的实例通常是类中的 private static字段,这些字段与某一个线程的状态关联起来(例如,用户 ID 或交易 ID)

例如,下面的类生成每个线程唯一的局部标识符。 线程 ID 是在第一次调用 UniqueThreadIdGenerator.getCurrentThreadId() 时分配的,在后续调用中不会更改。

  import java.util.concurrent.atomic.AtomicInteger;

 public class UniqueThreadIdGenerator {

     private static final AtomicInteger uniqueId = new AtomicInteger(0);

     private static final ThreadLocal < Integer > uniqueNum = 
         new ThreadLocal < Integer > () {
             @Override protected Integer initialValue() {
                 return uniqueId.getAndIncrement();
         }
     };
 
     public static int getCurrentThreadId() {
         return uniqueId.get();
     }
 } // UniqueThreadIdGenerator
 

每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。

使用

  • 在类中定义一个static的ThreadLocal,ThreadLocal内部有一个map保存每个线程的值;多个线程执行时,根据Thread.getCurrentThread()获取其对应的值。

private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
	public Integer initialValue() {
		return 0;
	};
};


public class TestThreadLocal {
    //多个线程共享使用,内部有map,保存每个线程的值
    private static final ThreadLocal<Integer> value = new ThreadLocal<Integer>() {

        @Override

        protected Integer initialValue() {

            return 0;

        }

    };

    public static void main(String[] args) {

        for (int i = 0; i < 5; i++) {

            new Thread(new MyThread(i)).start();

        }

    }


MyThread的run方法中
    public void run() {

            System.out.println("线程" + index + "的初始value:" + value.get());

            for (int i = 0; i < 10; i++) {

                value.set(value.get() + i);

            }

            System.out.println("线程" + index + "的累加value:" + value.get());

        }


    
}

代码分析

ThreadLocal类实现了三个接口

  • Serializable 支持序列化

ThreadLocal的变量

  • private final char value[] 保存字符

字符数组和offset及count都是final的,必须在构造方法中初始化,之后不能修改。

构造方法

  • public ThreadLocal() 空实现

其他方法

  • public T get() 获取值
  • public void remove()
  • public void set(T value)
//获取map中的值,首次调用时为null,会执行setInitialValue方法,
public T get() {
    Thread t = Thread.currentThread();//获取当前线程实例
    ThreadLocalMap map = getMap(t);//获取该线程实例对应的Map
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null)
            return (T)e.value;
    }
    //首次调用时
    return setInitialValue();
}

//首次调用get会调用该方法,其逻辑为创建map,调用initialValue()并设置到map中
private T setInitialValue() {
    T value = initialValue();//调用initialValue方法获取初始值,该方法会被重写
    Thread t = Thread.currentThread();//获取当前线程
    ThreadLocalMap map = getMap(t);//获取线程对应的Map
    if (map != null)
        map.set(this, value);//不为空,设置值
    else
        createMap(t, value);//为空,创建map并设置值
    return value;
}

ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;//ThreadLocal.ThreadLocalMap threadLocals
}

ThreadLocalMap是ThreadLocal的内部类,ThreadLocalMap内部有一个Entry类,保存值

//设置线程的value,若无map,则创建后再设置
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

总结

posted @ 2017-02-12 23:00  尅皮埃  阅读(144)  评论(0)    收藏  举报