您现在的位置是:首页 > 文章详情

Java中的ThreadLocal

日期:2018-05-07点击:351

Java中的ThreadLocal

变量值的共享可以使用public static变量的形式,所有线程可以共享一个变量。如果我们想实现一个线程都有自己的共享变量该如何解决呢,这里就要用到Java中的ThreadLocal类。

类ThreadLocal主要解决的就是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存放数据的盒子,盒子中可以存储每个线程的私有数据

我们先看下列代码

public static void main(String[] args) throws InterruptedException { ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){ @Override protected Integer initialValue() { return 0; } }; threadLocal.set(100); System.out.println("主线程中的值:"+threadLocal.get()); Thread t = new Thread(){ @Override public void run() { threadLocal.set(200); System.out.println("线程t中的值:"+threadLocal.get()); } }; t.start(); }

代码定义了一个ThreadLocal对象,然后在主线程中,给ThreadLocal对象放入100,而线程t则放入200,并打印。结果如下

可见,每个线程都取到了自己存入的那个值。那么它到底是怎么实现的呢,让我们来分析分析吧

首先先介绍一下ThreadLocal的一些主要方法

1、initalValue方法

protected T initialValue() { return null; }

initalValue方法,表示默认值,可见是null,但为了安全起见,我们在初始化ThreadLocal对象时采用匿名内部类来重写这个方法,以防止空指针异常。也就是这样:

ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){ @Override protected Integer initialValue() { return 0; } };

2、get方法

public T get() { //获取当前线程对象 Thread t = Thread.currentThread(); //取出线程类中的ThreadLocalMap ThreadLocal.ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocal.ThreadLocalMap.Entry e = map.getEntry(this); //如果Map不为空并且该线程确实存入了变量,则返回存入的变量 if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } //Map为空,返回默认值 return setInitialValue(); }

这里要说到,每个线程中都维护了一个ThreadLocalMap对象,这个Map就存储着你所存入的值,下面会说到。

3、set方法

public void set(T value) { //获取当前线程对象 Thread t = Thread.currentThread(); //根据线程获取线程中的ThreadLocalMap ThreadLocal.ThreadLocalMap map = getMap(t); //如果map不为空则直接存入值 if (map != null) map.set(this, value); //如果map为空,则创建Map并存入值 else createMap(t, value); }

4、remove方法

public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }

remove是移除所存入的值

5、getMap方法

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

根据线程去获得线程中的ThreadLocalMap对象

我们可以打开Thread类源码

/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;

这就是Thread类中的ThreadLocalMap对象,默认为空。只有你在使用ThreadLocal为线程保存私有属性时才会创建。

6、createMap方法

void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }

将线程中的ThreadLocalMap对象实例化并写入存入值

接下来就要看存储数据的ThreadLocalMap

static class ThreadLocalMap { //Map节点,注意key是ThreadLocal而不是Thread static class Entry extends WeakReference<ThreadLocal<?>> { Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } //构造方法 ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) { table = new ThreadLocal.ThreadLocalMap.Entry[INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new ThreadLocal.ThreadLocalMap.Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY); } }

Map很简单,只不过要注意的是Map的键是ThreadLocal而不是Thread。

总结

1、ThreadLocal是为了解决每个线程绑定自己的值

2、ThreadLocal默认值为null,所以有时候为了安全,初始化时使用匿名内部类来重写initalValue方法

3、每个线程对象内部都维护了一个ThreadLocalMao对象

4、ThreadLocalMap的键是ThreadLocal而不是Thread

5、ThreadlLocal可能会发生内存泄漏,所以在使用完ThreadLocal之后调用remove方法清除数据。

原文地址http://www.bieryun.com/3687.html

原文链接:https://yq.aliyun.com/articles/590826
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章