ThreadLocal

ThreadLocal

应用场景

主要用于做数据隔离,保证同一个变量在不同线程下操作时互不干扰,可以理解为每个线程单独复制一份变量保存在线程中,对保存的副本就行操作。
一个是用于上下文通信,因为ThreadLocal使用后如果步手动移除,value会一直保存(可能会发生内存泄漏),所以当一条线程一直存在的时候,可以利用这个特性对上下文都用到的对象进行存储,不用频繁的传参数。
第二个是多线程的安全问题,如SimpleDateFormat,我们使用SimpleDateFormat的parse()方法,内部有一个Calendar对象,调用SimpleDateFormat的parse()方法会先调用Calendar.clear(),然后调用Calendar.add(),如果一个线程先调用了add()然后另一个线程又调用了clear(),这时候parse()方法解析的时间就不对了。这个时候要保证各线程之间的操作互不干扰,可以使用ThreadLocal对各个线程进行隔离操作。

如何实现?

ThreadLocal其实并不是一个实例,可以理解为一个代理公司,实际操作的是Thread中的ThreadLocals对象,而用户创建的每一个ThreadLocal都会对应一个hashCode值,作为key存储在ThreadLocals中,当某个线程调用某个ThreadLocal的get、set方法时,首先获得当前线程的ThreadLocals,然后再根据使用的ThreadLocal获得HashCode值,找到对应的key-value,进行操作。

ThreadLocals

ThreadLocals是一个实例化的ThreadLocalMap对象,ThreadLocalMap是ThreadLocal的静态内部类,在某个Thread中初始化为null,

//Thread类中代码片段
ThreadLocal.ThreadLocalMap threadLocals = null;
//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;
            }
        }

ThreadLocalMap

key属于弱引用,容易被GC,value属于强引用,所以容易出现value一直存在,导致内存泄漏,所以应该用完就remove

关系

在这里插入图片描述

大概就是这么个关系,Thread中存储有实例化的ThreadLocalMap对象,变量名叫ThreadLocals,其中存有键值对,key是ThreadLocal的HashCode,value是ThreadLocal+其set值,当使用某个ThreadLocal的时候,先获得当前调用ThreadLocal的线程,然后再根据ThreadLocal的HashCode找到其对应的map,然后对Map中的value进行操作。但是要注意内存泄漏,使用结束后即使remove

InheritableThreadLocal

使用InheritableThreadLocal可以实现多个线程访问ThreadLocal的值,我们在主线程中创建一个InheritableThreadLocal的实例,然后在子线程中得到这个InheritableThreadLocal实例设置的值。

private void test() {    
final ThreadLocal threadLocal = new InheritableThreadLocal();       
threadLocal.set("帅得一匹");    
Thread t = new Thread() {        
    @Override        
    public void run() {            
      super.run();            
      Log.i( "张三帅么 =" + threadLocal.get());        
    }    
  };          
  t.start(); 
} 

如果线程的inheritThreadLocals变量不为空,比如我们上面的例子,而且父线程的inheritThreadLocals也存在,那么我就把父线程的inheritThreadLocals给当前线程的inheritThreadLocals。

参考文章

感谢大佬
如果有错误,还请大佬指出。非常感谢。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值