美文网首页
「Java 路线」| ThreadLocal

「Java 路线」| ThreadLocal

作者: 彭旭锐 | 来源:发表于2021-01-02 22:57 被阅读0次

    点赞关注,不再迷路,你的支持对我意义重大!

    🔥 Hi,我是丑丑。本文 「Java 路线」| 导读 —— 他山之石,可以攻玉 已收录,这里有 Android 进阶成长路线笔记 & 博客,欢迎跟着彭丑丑一起成长。(联系方式在 GitHub)


    前言

    • ThreadLocal 是解决多线程并发安全的一种解决方案,与 synchronized 有本质区别;
    • 在这篇文章里,我将献上 ThreadLocal 的使用方法 & 源码分析。如果能帮上忙,请务必点赞加关注,这真的对我非常重要。

    目录


    1. 前置知识

    这篇文章的内容会涉及以下前置 / 相关知识,贴心的我都帮你准备好了,请享用~


    2. 简介

    2.1 定义

    ThreadLocal 是一种 Thread-Specific Storage 的多线程编程模式,即:一个入口为多个线程分配不同的副本。由于线程间在某一时刻访问的并非同一个对象,这样就避免了多线程的数据共享,也就避免了并发安全问题。

    2.2 使用场景

    • 以空间换时间: 相对于Synchronized 等互斥锁避免了上下文切换损耗,有助于提高吞吐量;

    • 线程级别的单例: 一般的单例对象是进程单例的,使用 ThreadLocal 可以轻松实现线程级别单例;

    • 共享参数: 如果一个模块有非常多地方需要使用同一个变量,相比于在每个方法中重复传递同一个参数,使用 ThreadLocal 作为一个全局变量也许是另一种选择方式。

    2.3 编程规约

    记得吗?《阿里巴巴Java开发手册》中提到过关于 ThreadLocal 的编程规约,如下所示:

    • 5.【强制】SimpleDateFormate 是线程不安全的类,一般不要定义为 static 变量,如果定义为static,必须加锁,或者使用 DateUtils 工具类。正例:
    private static final ThreadLocal<DataFormat> df = new ThreadLocal<DateFormat>(){
        @Override
        protected DateFormat initialValue(){
            return new SimpleDateFormat("yyyy-MM-dd");
        }
    };
    

    说明: 如果是JDK8的应用,可以使用 Instant 代替 Date,LocalDateTime 代替 Calendar,DateTimeFormatter 代替 SimpleDateFormat,官方给出的解释:simple beautiful strong immutable thread-safe.

    • 15.【参考】(原文过于啰嗦,以下为笔者转述)ThreadLocal 变量建议使用 static 修饰,可以保证变量在类初始化时创建,所有类实例可以共享同一个静态变量。

    提示:第 4 节 使用示例 中,ThreadLocal 变量就是使用 static 修饰的。


    3. 使用介绍


    4. 使用示例

    作为一枚 Android 党,我就以熟悉的 Handler 机制中对 ThreadLocal 的应用作为例子:

    android.os.Looper.java

    public class Looper {
    
        1、静态 ThreadLocal 变量,所有类实例共享同一个 ThreadLocal 变量
        static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    
        private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            
            2、设置 ThreadLocal 变量的值
            sThreadLocal.set(new Looper(quitAllowed));
        }
    
        public static Looper myLooper() {
            3、获取 ThreadLocal 变量的值
            return sThreadLocal.get();
        }
    
        public static void prepare() {
            prepare(true);
        }
        ...
    }
    

    要点如下:

    • 1、ThreadLocal 被声明为 static final变量,泛型参数为 Looper,表示 ThreadLocal 变量接受 Looper类型的值;
    • 2、Looper.prepare() 中调用ThreadLocal#set()设置 当前线程 的 Looper;
    • 3、Looper.myLooper()中调用ThreadLocal#get()获取 当前线程 的 Looper。

    我们可以画出 Looper 中访问 ThreadLocal 的 Timethreads 图,不同线程访问的是不同的 Looper 对象,线程间不存在共享资源


    5. 源码分析


    6. 总结


    参考资料


    创作不易,你的「三连」是丑丑最大的动力,我们下次见!

    相关文章

      网友评论

          本文标题:「Java 路线」| ThreadLocal

          本文链接:https://www.haomeiwen.com/subject/qnueoktx.html