ThreadLocal 基本使用

  • ThreadLocal
    很多地方叫做线程本地变量,也有些地方叫做线程本地存储,ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
    它本身是为线程安全和某些特定场景的问题而设计的。
    在这里插入图片描述
    先了解一下ThreadLocal类提供的几个方法:
public T get() { }  
public void set(T value) { }  
public void remove() { }  
protected T initialValue() { } 

get()方法是用来获取ThreadLocal在当前线程中保存的变量副本,set()用来设置当前线程中变量的副本,remove()用来移除当前线程中变量的副本,initialValue()是一个protected方法,一般是用来在使用时进行重写的,它是一个延迟加载方法.

public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

第一句是取得当前线程,然后通过getMap(t)方法获取到一个map,map的类型为ThreadLocalMap。然后接着下面获取到<key,value>键值对,注意这里获取键值对传进去的是 this,而不是当前线程t。如果获取成功,则返回value值。 如果map为空,则调setInitialValue方法返回value。

/* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;
 /**
     * Get the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param  t the current thread
     * @return the map
     */
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

ThreadLocalMap的Entry继承了WeakReference,并且使用ThreadLocal作为键值。

static class ThreadLocalMap {

        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

setInitialValue() 如果map不为空,就设置键值对,为空,再创建Map,看一下createMap的实现

 /**
     * Variant of set() to establish initialValue. Used instead
     * of set() in case user has overridden the set() method.
     *
     * @return the initial value
     */
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

首先,在每个线程Thread内部有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,这个threadLocals就是用来存储实际的变量副本的,键值为当前ThreadLocal变量,value为变量副本(即T类型的变量)。 初始时,在Thread里面,threadLocals为空,当通过ThreadLocal变量调用get()方法或者set()方法,就会对Thread类中的threadLocals进行初始化,并且以当前ThreadLocal变量为键值,以ThreadLocal要保存的副本变量为value,存到threadLocals


ThreadLocal的应用场景:
最常见的ThreadLocal使用场景为 用来解决数据库连接、Session管理等。


实践:

public class ThreadLocalTest  {

    private static final ThreadLocal<Integer> LOCAL = new ThreadLocal(){
        // 覆盖初始化方法
        @Override
        public Integer initialValue() {
            return 0;
        }
    };

    // 下一个序列号
    public int getNextNum() {
        LOCAL.set(LOCAL.get() + 1);
        return LOCAL.get();
    }

    private static class TestClient extends Thread {
        private ThreadLocalTest sn;
        public TestClient(ThreadLocalTest sn) {
            this.sn = sn;
        }
        // 线程变量加加
        @Override
        public void run() {
            for (int i = 0; i < 3; i++) {
                System.out.println(Thread.currentThread().getName()  +"  Num:" +  sn.getNextNum());
            }
        }
    }

    public static void main(String[] args) {
        ThreadLocalTest test = new ThreadLocalTest();
        new TestClient(test).start();
        new TestClient(test).start();
        new TestClient(test).start();

    }
}

测试结果:

在这里插入图片描述


  • 编写工具类实现数据在同一个线程上的共享
public class ThreadUtils {

    private static final ThreadLocal<Object> LOCAL = new ThreadLocal<>();

    public static void  setValue( Object value ){
        LOCAL.set(value);
    }

    public static Object getValue(){
       return LOCAL.get();
    }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值