zoukankan      html  css  js  c++  java
  • ThreadLocal的实现

    0.简介:创建线程局部变量的类

    使用ThreadLocal创建的变量只能被当前线程访问,其他线程则无法访问和修改。

    • 内部类ThreadLocalMap实现,key是变量,value是所在的线程。

    用法如下:

    private void testThreadLocal() {
        Thread t = new Thread() {
            ThreadLocal<String> mStringThreadLocal = new ThreadLocal<>();
    
            @Override
            public void run() {
                super.run();
                mStringThreadLocal.set("localValue"); // 设置值
                mStringThreadLocal.get(); // 获取值
            }
        };
    
        t.start();
    }

    1.如何实现:依靠内部类ThreadLocalMap

    set是如何实现的?

    • 首先获取当前线程
    • 利用当前线程作为句柄获取一个ThreadLocalMap的对象
    • 如果ThreadLocalMap对象不为空,则设置值;否则创建这个ThreadLocalMap对象并设置值
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

    下面是一个利用Thread对象作为句柄获取ThreadLocalMap对象的代码:

    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

    可以看出一个Thread实例就有一个ThreadLocalMap对象。

    get是如何实现的

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

    3.总结

    实际上ThreadLocal的值是放入了当前线程的一个ThreadLocalMap实例中,所以只能在本线程中访问,其他线程无法访问。

    ThreadLocal的实例以及其值仍然存放在JVM的堆。

    4.问题

    4.1 ThreadLocal会导致内存泄露么

    如果应用使用了线程池,那么之前的线程实例处理完之后,会再次被复用,所以ThreadLocal变量会一直存在。

    • 不会发生内存泄露,ThreadLocalMap的内部实现是弱引用的,可以被JVM回收。
    static class ThreadLocalMap {
    
    /**
    * The entries in this hash map extend WeakReference, using
    * its main ref field as the key (which is always a
    * ThreadLocal object).  Note that null keys (i.e. entry.get()
    * == null) mean that the key is no longer referenced, so the
    * entry can be expunged from table.  Such entries are referred to
    * as "stale entries" in the code that follows.
    */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;
    
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
    }

    4.2 使用场景

    • 实现单个线程单例以及单个线程上下文信息存储,比如交易id等
    • 实现线程安全,非线程安全的对象使用ThreadLocal之后就会变得线程安全,因为每个线程都会有一个对应的实例
    • 承载一些线程相关的数据,避免在方法中来回传递参数
  • 相关阅读:
    codeforces C. No to Palindromes!
    codeforces D. Pashmak and Parmida's problem
    codeforces C. Little Pony and Expected Maximum
    codeforces D. Count Good Substrings
    codeforces C. Jzzhu and Chocolate
    codeforces C. DZY Loves Sequences
    codeforces D. Multiplication Table
    codeforces C. Painting Fence
    hdu 5067 Harry And Dig Machine
    POJ 1159 Palindrome
  • 原文地址:https://www.cnblogs.com/byrhuangqiang/p/6338106.html
Copyright © 2011-2022 走看看