ThreadLocal

1.ThreadLocal为什么能做到线程隔离?

复制代码
public class ThreadLocal1 {
    static ThreadLocal<People> t1 = new ThreadLocal<>();

    public static void main(String[] args) {
        new Thread(()->{
            try {
                Thread.sleep(1000);
                t1.set(new People("zhangsan"));
                System.out.println(t1.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(()->{
            try {
                Thread.sleep(2000);
                System.out.println(t1.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }


    static class People{
        String name = null;
        public People(String name) {
            this.name = name;
        }
    }
}
复制代码

 

 可以看到t1是一个全局变量,为什么在第一个线程中塞入值,并可以打印里面对象。可是在第二个线程中打印t1里面的对象却是空的。这就是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;
    }
t.threadLocals是每个线程里面的全局变量。我们不用看set里面代码具体做了什么。我们大致可以看出来,他是从每个线程里面的threadLocals的key获取一个map。

应用spring的事务。在一个事务中,假设有2个方法,对应着有2个Connection,因为事务是要保证要么都成功,要么就失败。所以Connection肯定要保证同一个。但是Connection都是从连接池中注入的,怎么保证相同的呢。
这时候就是ThreadLocal起作用了,可以在第一个连接从连接池注入的时候,就把这个连接对象放到ThreadLocal中,之后的连接直接从这里面拿,这样就能保证一个线程的Conncetion是同一个了。

但有时候会有疑问,为什么不用传参,传参也能够导致一个对象一致性。其实传参也是可以的,但是方法调用过多的时候,那时候参数一层套一层,太过累赘。也可以使用静态变量来保证,但是会造成整个上下文的污染,本来能线程
中解决的,干嘛要用全局变量来呢。


2.ThreadLocal为什么要设置成弱引用
首先是static ThreadLocal<People> t1 = new ThreadLocal<>()一个强引用。然后在ThreadLocal对象中set值的时候

 

 我们又可以看到一个当前线程的一个Map:threadLocals对象又指向了ThreadLocal引用。如果这个map指向是个强引用怎么办,我们就算把t1=null,这个ThreadLocal还是不能被垃圾回收了。如果这个编程弱引用,那么当t1置为null后,这个ThreadLocal就可以被垃圾回收了。

复制代码
 private void set(ThreadLocal<?> key, Object value) {

            // We don't use a fast path as with get() because it is at
            // least as common to use set() to create new entries as
            // it is to replace existing ones, in which case, a fast
            // path would fail more often than not.

            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();

                if (k == key) {
                    e.value = value;
                    return;
                }

                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }
复制代码
复制代码
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

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

 

posted @   WXY_WXY  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示