ThreadLcoal

如何使用ThreadLocal

public class ThreadLocalDemo {
    private static ThreadLocal<String> local = new ThreadLocal<>();
    private static String notLocal = new String();

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                local.set("我是线程0");
                notLocal = "我是线程0";
                method();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                local.set("我是线程1");
                notLocal = "我是线程1";
                method();
            }
        }).start();
    }

    public static void method(){
        System.out.println(Thread.currentThread().getName()+"   local : " + local.get());
        System.out.println(Thread.currentThread().getName()+"notLocal : " + notLocal);
    }
}

可能出现的结果

Thread-0   local : 我是线程0
Thread-1   local : 我是线程1
Thread-1notLocal : 我是线程1
Thread-0notLocal : 我是线程1

ThreadLocal的内存泄漏问题

要搞清楚这个问题,需要阅读源码

ThreadLocal机制结构

ThreadLcoal_第1张图片
ThreadLcoal_第2张图片

public class ThreadLocal<T> {

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

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


	static class ThreadLocalMap {

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

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



}

ThreadLocal的运行机制是,在Thread内部有一个Map实例,这个Map实例以ThreadLcoal实例作为key,要保存的对象作为value。如果用使用实例中的代码来说,那就是线程0和线程1中都有一个Map对象,然后这2个map对象都以ThreadLcoal local作为key,线程0的value就是“我是线程0”;线程1的value就是“我是线程1”。
这样一来,就可以形成线程作用域。因为对于ThreadLocal local而言,它在每一个线程中的Map实例里面,都放置了一个String对象。获取的时候,也是从当前线程的map中获取的。

为什么ThreadLocal自己实现了ThreadLocalMap,不使用现成的HashMap等?
别的方面我不清楚,但是最重要的一个原因就是为了解决内存泄漏问题。看ThreadLocalMap的源码可以发现,这个Map实现中,它的key是弱引用。

ThreadLocal为什么会出现内存泄漏问题,别人早就研究的很透彻,且写了很多博客,在这里不再说明。
总之一句话,内存泄漏是因为有不再使用的对象没有被回收,如果ThreadLocalMap中的key,也就是ThreadLocal被回收了,但是Map的value没有被回收,就发生了内存泄漏。如果使用线程被回收,那么自然value也会跟着被回收,影响不大。但如果使用了线程池,Thread就不会被回收,那么value就会一直存在,导致内存泄漏。所以需要掌握正确的ThreadLocal使用姿势。

ThreadLocal 定义,以及是否可能引起的内存泄露(threadlocalMap的Key是弱引用,用线程池有可能泄露)

你可能感兴趣的:(java,java,ThreadLocal)