每日一面——什么是ThreadLocal?

菜鸡每日一面系列打卡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原子类的理解

学习 | 工作 | 分享

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

只有你想不到,没有你学不到

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值