【连载 13】ThreadLocal 类
2.8 ThreadLocal
在使用 Java 进行性能测试的过程中,将线程共享的变量通过用例设计优化转换成线程独享,是一种非常高效的解决线程安全问题的思路。java.lang.ThreadLocal 可以不必提前确定线程的数量,不必提前分配每个线程所需要的对象,直接全局定义一个 java.lang.ThreadLocal 对象,在多线程编程中使用 java.lang.ThreadLocal 提供的操作 API 即可完成线程独享对象的创建、修改和其他管理操作。
2.8.1 基础方法
ThreadLocal 实现原理基于每个线程都维护一个 ThreadLocalMap,这个映射表的键是 ThreadLocal 实例,值是对应的线程局部变量。这样,每个线程都可以拥有自己的独立变量副本,不受其他线程影响。
首先我们看一下如何创建一个 java.lang.ThreadLocal 对象:
创建方法需要声明泛型,下面是 ThreadLocal 的无参构造方法:
该方法获取到的独享对象默认值是 null,如果你想设置其他默认值,可以使用以下语法:
亦或者使用 java.lang.ThreadLocal#withInitial 方法创建 ThreadLocal 对象:
initialValue 方法内容如下:
使用该方法会创建一个 ThreadLocal 子类 java.lang.ThreadLocal.SuppliedThreadLocal,该类重写了 java.lang.ThreadLocal.SuppliedThreadLocal#initialValue 方法,内容如下:
其次我们对于变量两个最基本的操作:获取和修改。
获取:java.lang.ThreadLocal#get
修改:java.lang.ThreadLocal#set
API 非常简单,这里需要注意的就是返回值和参数值的类型需要与 ThreadLocal 创建是定义的泛型类型保持一致。
2.8.2 最佳实战
在性能测试中,ThreadLocal 通常用来将共享对象转换成独享解决线程安全的问题。下面用一个案例演示 ThreadLocal 最佳实战:
控制台输出:
可以看到,每个线程打印的初始值都是一样的,重新赋值之后,每个线程打印的值都变得不一样了。这就说明每个线程实际获取的对象并不是同一个对象,也就实现了将共享对象转换成独享对象的设计思路,解决了线程安全的问题。
2.8.3 使用场景
除了以上使用场景外,java.lang.ThreadLocal 在性能测试使用的场景并不多。但在 ThreadLocal 使用过程中,需要注意潜在的内存泄漏问题。
如果 ThreadLocal 实例在某个类中定义为 static,而该类又被类加载器加载,那么这个 ThreadLocal 对象将一直存在于内存中,直到线程结束或者手动调用 remove()方法将其移除。
所以在性能测试中如果使用 ThreadLocal 来解决线程安全问题,需要对线程管理更加严格。对于新手而言,使用最佳实战中的方式是安全可靠的,若还是无法满足需求,则应该抛弃 ThreadLocal,寻求其他简单、可靠的解决方案。
书的名字:从 Java 开始做性能测试 。
如果本书内容对你有所帮助,希望各位不吝赞赏,让我可以贴补家用。赞赏两位数可以提前阅读未公开章节。我也会尝试制作本书的视频教程,包括必要的答疑。
版权声明: 本文为 InfoQ 作者【FunTester】的原创文章。
原文链接:【http://xie.infoq.cn/article/eac887ef2c6d3d5241d87bdb8】。文章转载请联系作者。
评论