Java基础-ThreadLocal

https://zhuanlan.zhihu.com/p/20213204

http://blog.xiaohansong.com/2016/08/06/ThreadLocal-memory-leak/

This class provides thread-local variables. These variables differ fromtheir normal counterparts in that each thread that accesses one (via itsgetorsetmethod) has its own, independently initializedcopy of the variable.ThreadLocalinstances are typically privatestatic fields in classes that wish to associate state with a thread (e.g.,a user ID or Transaction ID).

ThreadLocal类用来提供线程的局部变量。

这种变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量。

ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程的上下文。

总结:ThreadLocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。

思考:其实目的很简单,就是要将这个变量和线程绑定起来,通过如线程id等唯一标识就能获取到这个变量。如果是自己设计的话,会怎么样设计?最简单的一种思路应该是:ThreadLoacl,提供一个类似map的成员变量,key - threadId, value是一个键值对(map或entry):key -objKey, value -objValue。然后通过线程id和objKey,获取真正的value,so easy~!是的,好像早期jdk就是类似这样实现的?

继续思考:当线程数量增多时,ThreadLocal将会变得非常庞大。于是想着将这些变量交给Thread各个线程自己来存储,这是个好主意,Thread中增加一个map,key -objKey, value -objValue。

事实也确实是如此,后面的版本里,Thread类增加了一个成员变量threadLocals,ThreadLocal.ThreadLocalMap threadLocals 这就更加有趣了,这里先不管ThreadLocal和ThreadLocalMap的关系。我们暂且知道threadLocals 是一个map,就是存key - value的。稍微看下ThreadLocalMap,会发现里面存的是个Entry,key是ThreadLocal的WeakReference弱引用,先不管什么是弱引用,暂时认为就是存的ThreadLocal自身,value就是真正的值了。ThreadLocalrequestId = new ThreadLocal(); requestId.set(id),requestId.get(),用法简单

也就是说,set之后threadLocals会加一条记录:key -requestId, value -id,每一个ThreadLocal只对应一个局部变量,如果另外还有其他局部变量,需要重新new一个。

这时候再来看一下,官方以下代码中的推荐用法,set和remove方法是额外加的。

public class ThreadIdHolder { // Atomic integer containing the next thread ID to be assigned private static final AtomicInteger nextId = new AtomicInteger(0); // Thread local variable containing each thread's ID private static final ThreadLocalthreadId = new ThreadLocal() {

        @Override

        protected Integer initialValue() {

            return nextId.getAndIncrement();

        }

    };

    // Returns the current thread's unique ID, assigning it if necessary

    public static int get() {

        return threadId.get();

    }


    public static void set(int id) {

    threadId.set(id);

    }


    public static void remove() {

    threadId.remove();

    }

}

以上用法通过一个外部类Holder来作为threadId变量的封装再看看官方说明:ThreadLocal instances are typically private static fields in classes希望是private static的字段,然后通过外部的static方法来提供访问或修改,为何推荐是private static的呢?ThreadLocalthreadId = new ThreadLocal()

1、当多个线程都持有个变量时,threadLocalMap中的key都是threadId,value是真正的值

  所以,threadId应该是个公共的,不属于具体某一个线程的,故static,否则还要将threadId传递给各个线程

  private的原因应该是不希望直接操作threadId了,而是通过封装来提供适当的操作权限。

2、就当只有一个线程,在不同的上下文中,传递threadId也比较麻烦,所以推荐static

所以ThreadLocal的使用场景,考虑以下:

1、当多个线程都有该局部变量,但各个线程的值需要互相隔离

2、单个线程中,在不同上下文中,经常要使用到某个变量时

当然如果不按推荐使用,例如,直接在某一个类中ThreadLocalthreadId = new ThreadLocal();

那么,这样的结果就是由具体某一个线程来完成实例化,然后传递给各个线程。这时候就特别要注意其生命周期,threadId是否会被回收。

由于,ThreadLocalMap的entry持有的是ThreadLocal的弱引用,如果没有强引用的情况下即被回收了,entry将引用不到ThreadLocal,

也就是说

继续上面的问题,entry引用不到ThreadLocal,就等于ThreadLocalMap中存了一些过期的变量,容易引起内存泄露。

于是,ThreadLocalMap在设计的时候也想到了,增加了一些保护措施,在其get/set等方法中会判断并清空这些key为空的Entry

但是最好的习惯还是用完就remove掉。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  • Android Handler机制系列文章整体内容如下: Android Handler机制1之ThreadAnd...
    隔壁老李头阅读 7,599评论 4 30
  • 前言 ThreadLocal很多同学都搞不懂是什么东西,可以用来干嘛。但面试时却又经常问到,所以这次我和大家一起学...
    liangzzz阅读 12,419评论 14 228
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 前段时间刚看了BBC出的纪录片《地球》。我一向对纪录自然环境的纪录片比较感兴趣,可能是比较喜欢其中令人赏心悦目的山...
    在改变的赵小赵阅读 136评论 0 1
  • 有些事, 不是看到希望才去坚持, 而是坚持了才看得到希望。
    乔伊乔一阅读 198评论 0 3