暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

每日一面——什么是ThreadLocal?

有理想的菜鸡 2020-05-21
166

菜鸡每日一面系列打卡19

每天一道面试题目 

助力小伙伴轻松拿offer

坚持就是胜利,我们一起努力!


题目描述

什么是ThreadLocal


题目分析

在之前的文章中曾经说过,线程安全的实现方式有三种:互斥同步非阻塞同步无同步方案。我们都知道(不知道的小伙伴请看【每日一面——谈谈你对synchronized关键字的理解】这篇中对线程安全的讲解),非线程安全的条件有三个:多线程环境共享变量没有保证共享变量的原子性、可见性、有序性


互斥同步与非阻塞同步的解决方式都是针对第三条进行处理,保证共享变量的原子性、可见性、有序性,从而保证线程安全;而无同步方案则不同,它是针对共享变量进行处理的。本文要讲到的ThreadLocal就属于无同步方案,在面试中,ThreadLocal也是面试官考查的常客。


接下来,随菜鸡一起去看看吧。


题目解答


01
简介


细心的读者会发现,每日一面的更新是有一道逻辑线的,这也是称之为一个系列的原因。这样做的好处是,尽可能保持知识的连贯性,从而在信息碎片化的时代给大家尽可能地还原完整的知识体系。就拿最近更新的并发编程方面的文章来说,菜鸡制作了下图来梳理知识内在的逻辑线。你品,你仔细品……



逻辑关系一目了然,而本文要讲述的主要内容就是字体为白色的内容:ThreadLocal


02
原理


一般情况下,我们创建的变量是可以被任何一个线程访问并修改的,这也就是我们提到的共享变量的概念。而ThreadLocal变量则为每个线程都设有该变量的本地副本,让每个线程绑定自己的值,没有了共享变量,也就不存在线程安全问题了。


接下来,老规矩,跟着菜鸡一起阅读源码!

    public class ThreadLocal<T{


        ......


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


    void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
    }


        ......
        
    static class ThreadLocalMap {


            static class Entry extends WeakReference<ThreadLocal<?>> {


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


            private static final int INITIAL_CAPACITY = 16;
            private Entry[] table;
            private int size = 0;
            private int threshold; // Default to 0
            
            ......
            
    }
    }


    通过源码,我们发现,ThreadLocal底层维护了一个定制化的哈希表,而get()操作(此处省略)和set()操作本质上都是在操作ThreadLocalMap


    同时,static class Entry extends WeakReference<ThreadLocal<?>>此处的弱引用值得注意,是一个可能出现内存泄漏的点。


    03
    示例


    接下来,我们通过一个demo,来演示一下ThreadLocal的使用。

      public class ThreadLocalTest implements Runnable {


      private ThreadLocal<Integer> number = ThreadLocal.withInitial(() -> 0);


      @Override
      public void run() {
      number.set((int) Thread.currentThread().getId());
      System.out.println(number.get());
      }


      public static void main(String[] args) {
      ThreadLocalTest test = new ThreadLocalTest();
      for (int i = 0; i < 10; i++) {
      Thread t = new Thread(test);
      t.start();
      }
      }


      }



      运行结果如下:

        > Task :ThreadLocalTest.main()
        12
        14
        10
        15
        11
        16
        13
        18
        19
        17


        BUILD SUCCESSFUL in 0s


        以上便是菜鸡对ThreadLocal的一些总结,供大家参考。至此,我们已经将三种解决线程安全的方法学习完毕,是时候自我总结一下啦!


        相关链接

        每日一面——谈谈你对synchronized关键字的理解

        每日一面——谈谈你对ReentrantLock的理解

        每日一面——什么是CAS算法?

        每日一面——谈谈你对Atomic原子类的理解



        学习 | 工作 | 分享

        👆长按关注“有理想的菜鸡

        只有你想不到,没有你学不到
        文章转载自有理想的菜鸡,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

        评论