便利店传说(1)

图片 1

最早接触到ThreadLocal是在阅读dianping的Cat-client,当时对它不是很精通,就摸索了一晃,大概领会是一种缓解线程安全题材的建制。今后再一次阅读《实战java高并发程序设计》时,又再度对它有了更深一步的询问。

“小孙小编有件工作要跟你说,有点不佳意思开口。”小时工业大学姑来到店里,工艺装备都还没换,就走进收银台对正在盘点货物的孙俊说道。

并发程序很重大的主旨就是涸泽而渔八线程安全的标题,最普遍的拍卖措施正是引入锁的编写制定;不过锁使得各样线程对临界区的选用功效变差,于是有了一种新的思绪,即各样线程独立管理有个别变量,变量的改动在线程中时独自的。就好比,之前锁的机制是玖拾玖个人签到,唯有三个签字薄;而未来ThreadLocal是种种人一张纸。

“哦,好的李四姨,您先进去里面把衣服换了啊,作者盘完那点东西就进来找你。”孙俊抬起初对李阿姨笑着说道,正在盘点的是一些滞销的捐躯品,数量不多,相当的慢就能够盘完。

但是上边包车型大巴场合,只是threadLocal的七个接纳场景。还有个例子,是在都市之中倒车。小明去上班要先做公交车在做地铁,要是每趟坐车都定票,那么时间效用很差。于是小明办理了一张通用的公共交通卡,公共交通车和大巴都能够刷。而小蓝小红也有诸如此类的公共交通卡,它们的公共交通卡相互之间是单身的。那正是ThreadLocal的效益!

孙俊是一家有名连锁方便人民群众店的店长,高校毕业刚刚八个月,结业前实习正是在有利于店里,结业后又一向回到做了店长。领导和同事都说他年轻又前进,以往在便利店行业里有所作为,他本身也接连笑呵呵地答应说,自个儿也看好这些行业以往的升华。而事实上,孙俊并不希罕那份工作,之所以一向坚定不移做着,是因为不亮堂偏离了该去做什么别的的作业,既然没有显明的其他想做的办事,那就安慰先搞好日前的吗。

故而说,ThreadLocal并不是化解线程共享难点,而是为了化解单个线程内部变量的独立性和参数字传送递的标题。

“美美,你进入收银吧,作者去里面看看李小姑有如何业务。”孙俊盘点完后,对正在货架前理货的美美说道。美美的名字其实叫刘梅,但她不欣赏别人叫她全名,刚进店里的时候就强烈供给大家随后都要叫她的外号‘美美’。

那正是说它的原理时怎样的吗?

“好的,你去啊。”纵然美美长相一般,但很活泼可爱,也聪明伶俐,才来上班半个多月,就差不离把店里全体的根基工作都学会了。

粗略,正是各种线程自身有多个Map,那些Map选用了线性探测法来存款和储蓄变量。接下来首要阅读下代码吧:

孙俊收拾好刚才盘点的货物,把收银台交给了美美,自身到个中办公去找李四姨了。路过刚才美美整理的货架时,孙俊发现有一包薯片搁在了货架的顶端。他拿起薯片朝着美美晃了晃,提示她干活要细致,然后顺手把薯片放回了原位。

public T get() {
    Thread t = Thread.currentThread();
    // 获取当前线程的localmap
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        // 用当前的变量作为key查询对象
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    // 如果不存在的话,初始化变量
    return setInitialValue();
}

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

“李大姑您刚才说有业务,说吧,什么事?”孙俊走进办公室,看到李二姑正坐在办公桌前签到,于是直接在边际摞着的两箱米酒上坐了下来。

重庆大学时尤其getEntry方法:

“小孙你忙完呀?”李大妈签完到,起身把签到表又挂回了墙上,没有再坐下,直接站着对孙俊说道。

private Entry getEntry(ThreadLocal<?> key) {
    // 通过当前key的hashcode与列表的长度做 &操作,判断存储的位置
    int i = key.threadLocalHashCode & (table.length - 1);
    Entry e = table[i];
    if (e != null && e.get() == key)
        return e;
    else
        // 如果不存在的话,进入getEntryAfterMiss方法
        // 这种情况,可能是key被回收掉了;也可能是hash冲突了
        return getEntryAfterMiss(key, i, e);
}
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
            Entry[] tab = table;
            int len = tab.length;
// 这里是典型的线性地址探测法
            while (e != null) {
                ThreadLocal<?> k = e.get();
                if (k == key)
                    return e;
                if (k == null)
                    expungeStaleEntry(i);
                else
                    i = nextIndex(i, len);
                e = tab[i];
            }
            return null;
        }        

“哪有忙完的时候,您先说您的作业,说完后自个儿再持续做自身的业务,您坐下说。”孙俊看到李姑姑脸上有个别面露难色,大约猜到了她要说的事情。

亟需专注的是,ThreadLocal里面包车型大巴内部存款和储蓄器结构是那样的:
图片 2
由于key是弱引用,因而在gc的时候会被回收掉。所以entry中会包罗key为null的值,那么那里会不会有内部存款和储蓄器泄漏呢?能够看一下expungeStaleEntry办法,在意识有value为null的时候,threadlocal会自动扫描别的的成分,看看有没有key为null的,要是有的话,一并移除。

“是那般的,前段时间我不是跟你们说过,作者媳妇怀了二胎嘛,此前时间短还在此起彼伏上班,以后还有五个月就要生了,已经休了产假在家里养胎了。小编是那般想的,作者在咱店里上班上到年终,然后就在家专门照顾儿媳妇,不能够来上班了。”李三姨看起来万分抱歉,顾而言他地好不便于才把事情说了出去。

万一为null,供给清理对应的value:

“那事啊,没难点的李四姨,您不用担心店里。”固然店里近来人口比较贫乏,可是孙俊能够知情,相比较起来,当然是李大妈家的政工更为主要。

private int expungeStaleEntry(int staleSlot) {
    Entry[] tab = table;
    int len = tab.length;

    // expunge entry at staleSlot
    tab[staleSlot].value = null;
    tab[staleSlot] = null;
    size--;

    // Rehash until we encounter null
    Entry e;
    int i;
    for (i = nextIndex(staleSlot, len);
         (e = tab[i]) != null;
         i = nextIndex(i, len)) {
        ThreadLocal<?> k = e.get();
        if (k == null) {
            e.value = null;
            tab[i] = null;
            size--;
        } else {
            int h = k.threadLocalHashCode & (len - 1);
            if (h != i) {
                tab[i] = null;

                // Unlike Knuth 6.4 Algorithm R, we must scan until
                // null because multiple entries could have been stale.
                while (tab[h] != null)
                    h = nextIndex(h, len);
                tab[h] = e;
            }
        }
    }
    return i;
}

“小孙小编跟你说,我当成觉得挺倒霉意思的,你看店里以往正缺人,而且即刻要度岁了,笔者此刻跟你说要走,太过意不去了。而且作者也挺舍不得你们的。”李四姨从孙俊还没到店里来做店长的时候,就在那些店做小时工了,孙俊来后,一贯挺照顾李大妈的。经常李二姨因为接送孙女上下学而迟到可能早走,孙俊没有说怎么,由此李四姨在店里忙的时候也日常会白白加班。

官方推荐应用private
static修饰,跟Java大神聊了下,总括一下ThreadLocal为啥推荐那样使用:

“李三姨您不要有顾虑,店里是相比较缺人,不过未来学生不是放寒假了呗,领导说已经招到一批寒假工了,过几天就会分配到店里。还有你以往要是想我们了,随时都足以到店里来看我们嘛,反正你家离大家店也不远。”孙俊也略微舍不得李三姑,日常上班不忙的时候,他平日跟李大妈聊天,纵然四个人年龄差距相比较大,但是能聊得来的话题照旧广大的。

  1. 推荐介绍用private修饰,是不向外部其余的靶子也能引用到,幸免困扰垃圾回收
  2. 引进使用static,笔者个人的接头是为着把目的存款和储蓄到点子去(static修饰的变量会储存在方法区),那样就算其中的Entry是弱引用,但出于变量在方法区,也不会在gc的时候被回收掉。<—个人理解哈,如有不对,还请指正

“好的,作者一定常常来。你跟领导涉嫌那么好,多要多个寒假工来协助呗。对了,小编带了你最欢跃吃的三鲜馅饺子,你下班后吃完了再走,作者带了挺多的。”李二姨上班的时候都会协调从家里带晚饭,平常都会多带一些给店里人吃,特别是和孙俊一起上班的时候。孙俊就算感到害羞,但看似吃了比不吃更能让李二姑春风得意,所以她新生也就不再推辞了。

应用

在cat的代码中:

public class DefaultMessageManager extends ContainerHolder implements MessageManager, Initializable, LogEnabled {
    // we don't use static modifier since MessageManager is configured as singleton
    private ThreadLocal<Context> m_context = new ThreadLocal<Context>();

    // 每个线程拥有独立的上下文信息
    private Context getContext() {
        if (Cat.isInitialized()) {
            Context ctx = m_context.get();

            if (ctx != null) {
                return ctx;
            } else {
                if (m_domain != null) {
                    ctx = new Context(m_domain.getId(), m_hostName, m_domain.getIp());
                } else {
                    ctx = new Context("Unknown", m_hostName, "");
                }

                m_context.set(ctx);
                return ctx;
            }
        }

        return null;
    }

    @Override
    public void end(Transaction transaction) {
        Context ctx = getContext();

        if (ctx != null && transaction.isStandalone()) {
            if (ctx.end(this, transaction)) {
                m_context.remove();
            }
        }
    }

“李小姨你太偏心了,只说让店长吃,都不给自家吃!”店里以往未曾顾客,美美到仓库里拿货把刚刚卖掉的补上,听到李四姨说有吃的,酸溜溜地对李二姨钻探。

“怎么不给你吃,小编正要出去跟你说呢,作者带了众多的,都有份。”李四姨一边笑着对美美说道,一边站起来走出了办公,到卖场里开头干活儿了。

“您好,欢迎光临。”李大妈刚走到卖场里,店门口红外感应器的语音就响了起来,孙俊给正在拿货的美美使了个眼神,美美立刻驾驭,放下货就走了出来。

李岳母和美美都走出来后,孙俊起身坐到了办公桌前,明天的电子版考勤还尚无做吧,先把它做完再去做此外业务呢,免得一会儿忙忘记了。互联网有个别不给力,在等候缓冲的小时里,孙俊在脑海中纪念着,自从做了便利店工作的话,已经淡忘具体有个别许人赶来店里工作今后又相差,就如很少有人可以一向坚韧不拔做那份工作对比长的日子。就拿自身毕业后驶来的这家店来说呢,刚来时店里的职工,方今只剩余李大姨壹位了,而他也相当慢就要离开了。新来的美美又能滴水穿石多久呢?是或不是也会像别的人一样,做了多少个月就厌倦了吧。

网页终于缓冲了出来,孙俊心想:这个也不是方今半会儿就能想出个所以然来的,依旧先做好近日的行事啊,不然又要突击了,自个儿曾经相当长日子尚无准时下过班了。于是她收起思绪,重新又投入到了劳作其中。