美文网首页
深度剖析ThreadLocal

深度剖析ThreadLocal

作者: 掩流年 | 来源:发表于2019-12-09 23:40 被阅读0次

概念

ThreadLocal是并发编程中的一种对象共享方式,从字面意思上看,我们大概能推断出它的用法是作为线程局部变量来使用的。它的好处是,可以存有每个线程独立的数据而互不影响。可以简单的把ThreadLocal理解为一个类似于HashMap的数据结构。更准确的说是WeakHashMap。可以简单来写一个简化版的ThreadLocal

class SimpleThreadLocal {
    static Map<String, String> map = new ConcurrentHashMap<>();
    private static CountDownLatch latch = new CountDownLatch(5);

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            int value = i;
            new Thread(() -> {
                map.put(Thread.currentThread().getName(), Integer.toString(value));
                latch.countDown();
            }).start();
        }
        latch.await();
        System.out.println(map);
    }
}

这就可以被作为一个ThreadLocal来使用了,在这个map中,key是它的名称,value可以作为每个线程独有的数据来存储。但实际上ThreadLocal却不是这么的简单,但也复杂不了多少。

深度解析

接下来看一段源码吧

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);
    }

上述展示了ThreadLocalput方法源码,看起来基本上是一目了然的,基于我们之上手写的ThreadLocal来说,不同的点在于,源码的map是线程独有的,而我们的map是共享的。这时候就要问自己一个问题,为什么要这么设计呢?
答案是,如果采用共享的map,当某个线程被销毁的后,它的数据会占用内存不能被回收。这样导致了很多垃圾数据的积累。所以使用单个线程自带map存储数据是相当方便的。

这时候又出现了新的问题,当我们使用线程池的时候,线程池中的核心线程不会被销毁,有时候线程会把较大的对象存入结构中,长时间的积累将导致内存泄漏。

避免的方式是,ThreadLocal提供了remove()接口,对于不需要的对象,要及时调用remove()方法去清理。

再来看下get()方法的源码

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

get()的逻辑从表面看来是个相当容易理解的,重点的深入到ThreadLocalMap中看看getMap的实现。

    static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

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

上述代码提供了ThreadLocalMap中的一个方法,我们能发现在其中有一个什么精巧的设计。我们可以把k当作线程实例,v当作值。整个Entry继承了WeakReference<ThreadLocal<?>>弱引用,弱引用的方式就是在Java虚拟机GC发现的时候,就可以立即回收。这样当外部的ThreadLocal强引用被回收的时候,这个Entry的key就会被置为null。

应用与注意事项

我们简单举个例子

   private static ThreadLocal<Connection> threadLocal = ThreadLocal.withInitial(() -> {
        try {
            return DriverManager.getConnection("url");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    });

可以很好的想到,ThreadLocal可以做数据库的连接池。或者web端的session等等。它的作用可以说是十分广泛。
在《Java高并发程序设计》这本书中,有个例子验证了共享一个变量和使用ThreadLocal对性能的影响,有兴趣可以读一读,条件以及得出的结论是:

条件:
4个线程
一千万的随机数循环

结论:
多线程共享一个Random 耗时:`13s`
使用ThreadLocal 耗时:`1.7s`

另一方面,我们需要注意的是,ThreadLocal相当于全局变量,如果滥用它将会导致代码的可重用性降低以及增加耦合度,这是格外需要注意的。

相关文章

  • 深度剖析ThreadLocal

    概念 ThreadLocal是并发编程中的一种对象共享方式,从字面意思上看,我们大概能推断出它的用法是作为线程局部...

  • 14-ThreadLocal类详细剖析

    ThreadLocal类详细剖析 对ThreadLocal的理解 JDK中的源码是这样描述ThreadLocal的...

  • ThreadLocal剖析

    ThreadLocal可以在多线程下实现各个线程的数据隔离 存储原理 直接看ThreadLocal的get()方法...

  • ThreadLocal源码剖析

    ThreadLocal源码剖析 ThreadLocal其实比较简单,因为类里就三个public方法:set(T v...

  • java多线程——ThreadLocal那些不为人知的细节

    今天我们来剖析一下ThreadLocal的源码。 说到ThreadLocal,我们在日常的开发工作中用的还是挺多的...

  • ThreadLocal源码剖析

    1.ThreadLocal概述 本文源码基于android 27。 1.1 简介 ThreadLocal提供了线程...

  • 深入剖析ThreadLocal

    概述 本文首发于个人技术博客[Java并发包学习七]解密ThreadLocal 相信读者在网上也看了很多关于Thr...

  • ThreadLocal源码剖析

    简述 ThreadLocal是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set(...

  • ThreadLocal源码剖析

    每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的。在线程...

  • spring5,mybatis,springboot源码深度剖析

    spring5,mybatis,springboot源码深度剖析教程源码分析视频框架15套java框架源码深度剖析...

网友评论

      本文标题:深度剖析ThreadLocal

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