美文网首页java
juc之五: ThreadLocal

juc之五: ThreadLocal

作者: suxin1932 | 来源:发表于2020-01-30 17:35 被阅读0次

    1. ThreadLocal (JDK版本)

    1.1 ThreadLocal 概述

    ThreadLocal方法及内部类.png

    1.2 Thread-ThreadLocal-ThreadLocalMap 关系

    Thread类有成员变量threadLocals (类型是ThreadLocal.ThreadLocalMap),
    也就是说每个线程有一个自己的ThreadLocalMap ,
    所以每个线程往这个ThreadLocal中读写隔离的,并且是互相不会影响的。
    
    一个ThreadLocal只能存储一个Object对象,
    如果需要存储多个Object对象那么就需要多个ThreadLocal!
    
    Thread-ThreadLocal-ThreadLocalMap.jpg

    1.2.1 ThreadLocalMap

    java对象的引用包括 :
    强引用,软引用,弱引用,虚引用 。
    
    因为这里涉及到弱引用,简单说明下:
    弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,
    无论内存是否充足,该对象仅仅被弱引用关联,那么就会被回收。
    
    当仅有ThreadLocalMap中的Entry的key指向ThreadLocal的时候,ThreadLocal会进行回收的!
    
    ThreadLocal被垃圾回收后,在ThreadLocalMap里对应的Entry的键值会变成null,
    但是Entry是强引用,那么Entry里面存储的Object,并没有办法进行回收,
    所以ThreadLocalMap 做了一些额外的回收工作。
    !!!虽然做了但是也会存在内存泄漏风险
    
    ThreadLocalMap.png ThreadLocal防止内存泄漏做的工作-->不够.jpg

    1.3 ThreadLocal的最佳实践(可以参考阿里巴巴java规范)

    ThreadLocal被垃圾回收后,在ThreadLocalMap里对应的Entry的键值会变成null,
    但是Entry是强引用,那么Entry里面存储的Object,并没有办法进行回收,所以ThreadLocalMap 做了一些额外的回收工作。
    #备注:
    很多时候,我们都是用在线程池的场景,程序不停止,线程基本不会销毁!!!
    
    由于线程的生命周期很长,如果我们往ThreadLocal里面set了很大很大的Object对象,
    虽然set、get等等方法在特定的条件会调用进行额外的清理,
    但是ThreadLocal被垃圾回收后,在ThreadLocalMap里对应的Entry的键值会变成null,
    但是后续再也没有操作set、get等方法了。
    
    #所以最佳实践
    应该在我们不使用的时候,主动调用remove方法进行清理。
    try {
        // 其它业务逻辑
    } finally {
        threadLocal对象.remove();
    }
    
    ThreadLocal最佳实践.jpg

    1.4 ThreadLocal用在什么地方?

    #应用场景概述
    >> 保存线程上下文信息,在任意需要的地方可以获取!!!
    >> 线程安全的,避免某些情况需要考虑线程安全必须同步带来的性能损失!
    
    #例如
    由于ThreadLocal的特性,同一线程在某地方进行设置,在随后的任意地方都可以获取到。
    从而可以用来保存线程上下文信息。
    
    常用的比如每个请求怎么把一串后续关联起来,就可以用ThreadLocal进行set,
    在后续的任意需要记录日志的方法里面进行get获取到请求id,从而把整个请求串起来。
    
    还有比如Spring的事务管理,用ThreadLocal存储Connection,
    从而各个DAO可以获取同一Connection,可以进行事务回滚,提交等操作。
    

    1.5 ThreadLocal应用示例

    1.5.1 用于存储线程信息

    package com.zy.tools.undefined.concurrent.threadlocal;
    
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    
    public class ThreadLocalDemo01 {
        private static final ExecutorService executor = Executors.newCachedThreadPool();
        private static ThreadLocal<String> threadLocal = new ThreadLocal<>();
        public static void main(String[] args) throws InterruptedException {
            CountDownLatch countDownLatch = new CountDownLatch(4);
            for (int i = 1; i < 5; i++) {
                int finalI = i;
                executor.submit(() -> {
                    try {
                        threadLocal.set(Thread.currentThread().getName() + " ---> " + finalI);
                        System.out.println(threadLocal.get());
                        countDownLatch.countDown();
                    } finally {
                        threadLocal.remove();
                    }
                });
            }
            countDownLatch.await(5L, TimeUnit.SECONDS);
            executor.shutdown();
        }
    }
    

    2. FastThreadLocal (Netty版本)

    参考资源
    https://mp.weixin.qq.com/s/yBLIbWs7bA0rjYj3Ypxd9g (JDK ThreadLocal)

    相关文章

      网友评论

        本文标题:juc之五: ThreadLocal

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