文档章节

ThreadLocal详解

无名猪
 无名猪
发布于 2016/08/08 15:12
字数 824
阅读 47
收藏 2
点赞 0
评论 0

     ThreadLocal翻译过来是本地线程的意思,但实际意义则不然,更贴切的英文其实应该是ThreadLocalVariable,本地线程变量,就更容易理解了。首先要明确的是ThreadLocal不是线程之间的变量共享,只是线程内部的一个本地变量,就如同源代码中的说法一样:

* This class provides thread-local variables.  These variables differ from
 * their normal counterparts in that each thread that accesses one (via its
 * <tt>get</tt> or <tt>set</tt> method) has its own, independently initialized
 * copy of the variable.  <tt>ThreadLocal</tt> instances are typically private
 * static fields in classes that wish to associate state with a thread (e.g.,
 * a user ID or Transaction ID).

下面就从源码角度详解ThreadLocal。  

     每个Thread都含有一个ThreadLocal.ThreadLocalMap的变量threadLocals,而ThreadLocalMap是一个HashMap的Entry[],而Entry则如下,其中的ThreadLocal是弱引用。

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

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

ThreadLocal的主要方法主要有get()和set().

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

get()方法首先取得当前的线程,然后取得当前线程的ThreadLocalMap,如果map不为null则再取出Entry,为空则初始化ThreadLocalMap并返回ThreadLoca默认值null,这里其实就是延迟初始化的很好的范例,当新建线程时ThreadLocal.ThreadLocalMap threadLocals = null;并没有初始化,而是当真正要使用的时候才进行初始化(如果先调用set()方法也会进行初始化)。

注意取ThreadLocalMap的参数为当前线程t,而取Entry参数则为this。

 public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

set方法也是先取得当前线程的ThreadLocalMap,如果map不为空则将当前threadlocal和value存放到Entry的hashMap中(方法与hashmap的putt方法类似),如果map为空则进程初始化。

从上面的源码和方法可以看出:ThreadLocalMap其实是ThreadLocal类的一个静态内部类,它实现了键值对的设置和获取(键为ThreadLocal,值为value),每个线程中都有一个独立的ThreadLocalMap,它所存储的值,只能被当前线程(currentThread)读取和修改。还有就是,ThreadLocalMap存储的键值对中的键是this对象指向的ThreadLocal对象,而值就是你所设置的对象了,这也就是为什么get和Set方法中为什么既有当前线程,又有this关键字了。跟线程同步,共享变量没有关系,只是线程内部的变量,线程内部使用,不必进行参数传递就可以进行对象访问。

下面就通过一个例子来说明ThredLocal<T>是如何实现线程之间互不干扰的。

package threadLearn;

public class Test {
    ThreadLocal<Long> longLocal = new ThreadLocal<Long>();
      
    public void set() {
        longLocal.set(Thread.currentThread().getId());        
    }
     
    public long getLong() {
        return longLocal.get();
    }
     
   
    public static void main(String[] args) throws InterruptedException {
        final Test test = new Test();

        test.set();
        System.out.println(Thread.currentThread().getName()+":"+test.getLong());    
               
        Thread thread1 = new Thread(){
            public void run() {
               test.set();
               System.out.println(Thread.currentThread().getName()+":"+test.getLong());               
            };
        };
        thread1.start();
        thread1.join();
         
        System.out.println(Thread.currentThread().getName()+":"+test.getLong());           	
    	}
}

执行结果如下:

main:1
Thread-0:9
main:1

前面说过ThreadLocalMap其中的ThreadLocal是弱引用,那会不会引发内存泄露呢?盗用一张图看下就可以一目了然了,在此不详细说明。为了避免发生内存泄露,建议使用remove方法。

 

© 著作权归作者所有

共有 人打赏支持
无名猪
粉丝 1
博文 9
码字总数 9618
作品 0
南京
程序员

暂无相关文章

10个免费的服务器监控工具

监控你的WEB服务器或者WEB主机运行是否正常与健康是非常重要的。你要确保用户始终可以打开你的网站并且网速不慢。服务器监控工具允许你收集和分析有关你的Web服务器的数据。 有许多非常好的服...

李朝强 ⋅ 20分钟前 ⋅ 0

压缩工具之zip-tar

zip 支持目录压缩。使用yum安装zip包,使用yum安装unzip包 zip 1.txt.zip 1.txt #将1.txt文件压缩,新生成的压缩文件为1.txt.zip,原文件保留 zip -r 123.zip 123/ #-r对目录操作。将123/目录...

ZHENG-JY ⋅ 21分钟前 ⋅ 0

Dubbo @Activate注解使用和实现解析

Activate注解标识一个扩展是否被激活和使用,可以放在定义的类上和方法上,dubbo用它在SPI扩张类定义上,标识这个扩展实现激活的条件和时机,先看下定义: /** * Activate * <p/> * ...

哲别0 ⋅ 27分钟前 ⋅ 0

6.5 zip压缩工具 tar打包 打包并压缩

1.tar tar命令格式 [-zjxcvfpP] filename tar -z:表示同时用gzip压缩。 -j:表示同时用bzip2压缩。 -J:表示同时用xz压缩。 -x:表示解包或者解压缩。 -t:表示查看tar包里的文件。 -c:表示建...

oschina130111 ⋅ 29分钟前 ⋅ 0

Linux系统工程狮养成记

如今的社会,随着时代的发展,出现了很多职业,像电子类,计算机类的专业,出现了各种各样的工程师,有算法工程师,java工程师,前端工程师,后台工程师,Linux工程师,运维工程师等等,不同...

六库科技 ⋅ 36分钟前 ⋅ 0

Linux 机器的渗透测试命令备忘表

如下是一份 Linux 机器的渗透测试备忘录,是在后期开发期间或者执行命令注入等操作时的一些典型命令,设计为测试人员进行本地枚举检查之用。 此外,你还可以从这儿(https://gbhackers.com/c...

寰宇01 ⋅ 37分钟前 ⋅ 0

windows 安装java开发环境,配置jdk

下载jdk安装文件 链接:https://pan.baidu.com/s/1UEKPjnAdMqNj612B39Pfsg 密码:ipqx 如果javac无法使用 1,检查环境变量名称中是否有空格。。。,去除后即可 2,将JAVA_HOME替换为原始路径...

阿豪boy ⋅ 39分钟前 ⋅ 0

简析log4j的实现方式

刚加入新公司,对日志的要求比较严格,对此特意花了几天时间看了一下log4j的源码,大概了解了一下log4j的实现方式,总结如下: log4j的实现分为两个步骤:log4j.xml的加载,logger的使用 这里...

zdatbit ⋅ 今天 ⋅ 0

win环境下jdk7与jdk8共存配置

1.jdk安装包 jdk安装包 安装步骤略 2.jdk等配置文件修改 在安装JDK1.8时(本机先安装jdk1.7再安装的jdk1.8),会将java.exe、javaw.exe、javaws.exe三个文件copy到了C:\Windows\System32,这...

泉天下 ⋅ 今天 ⋅ 0

windows profesional 2017 build problem

.net framework .... https://stackoverflow.com/questions/43330915/could-not-load-file-or-assembly-microsoft-build-frameworkvs-2017...

机油战士 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部