博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java中ThreadLocal使用及分析
阅读量:4109 次
发布时间:2019-05-25

本文共 4102 字,大约阅读时间需要 13 分钟。

0. ThreadLocal简单使用
  • ThreadLocal类的简单使用。下面(程序中)共有 10 个 ‘人’ 同时命令 ‘小李子’ 做点什么事情 : - ),代码如下(使用 ThreadLocal 完成统计方法的执行时间):
import java.util.Random;import java.util.concurrent.TimeUnit;public class Temp_4 {
public static void main(String[] args) throws InterruptedException {
Person person = new Person("小李子"); System.out.println(person.getName() + " begin to do"); int threadNum = 10; Thread[] workers = new Thread[threadNum]; for(int i = 0;i < threadNum;i++) {
workers[i] = new Thread(new Runnable() {
@Override public void run() {
person.toDoSomething(); } }, "t-" + i); } for(int i = 0;i < threadNum;i++) {
workers[i].start(); } for(int i = 0;i < threadNum;i++) {
workers[i].join(); } System.out.println("all works done."); }}class Person {
private static ThreadLocal
costTime = new ThreadLocal
(); private static Random random = new Random(); private final String name; public Person(String name) {
this.name = name; } public String getName() {
return name; } public void toDoSomething() {
costTime.set(System.currentTimeMillis()); // 上班打卡 String threadName = Thread.currentThread().getName(); int sleepTime = random.nextInt(1001); while(sleepTime == 0) {
sleepTime = random.nextInt(1001); } try {
TimeUnit.MILLISECONDS.sleep(sleepTime); // 小李子只想睡觉 } catch (InterruptedException e) {
e.printStackTrace(); } // 打卡下班 System.out.println(threadName + " command " + name + " to do something, cost time is " + (System.currentTimeMillis() - costTime.get()) / 1000.0 + "s"); }}

执行结果如下:

小李子 begin to dot-1 command 小李子 to do something, cost time is 0.083st-2 command 小李子 to do something, cost time is 0.193st-6 command 小李子 to do something, cost time is 0.396st-9 command 小李子 to do something, cost time is 0.41st-7 command 小李子 to do something, cost time is 0.461st-5 command 小李子 to do something, cost time is 0.488st-3 command 小李子 to do something, cost time is 0.494st-8 command 小李子 to do something, cost time is 0.575st-4 command 小李子 to do something, cost time is 0.668st-0 command 小李子 to do something, cost time is 0.803sall works done.

查看程序的运行结果,从中我并没有看出什么(-_- !),所以还是去看一眼 ThreadLocal 类的具体实现。(猜想:我们知道,ThreadLocal 可以实现:为每个线程保存一个对象,所以我猜测它的内部必定有一个数据结构/容器来维护每个线程及其持有的对象,该数据结构/容器要保证多线程安全,而且当线程终止后,ThreadLocal 最好还能够释放对该线程及其所持对象的引用)

1. ThreadLocal 类的具体实现
  • 从源代码开始。ThreadLocal 对外暴露的可供我们使用的方法总共只有 3 个:
    ThreadLocal公共方法
    该类仅仅只有一个无参的构造器方法,且该方法的方法体为空。
    先看 get 方法,该方法返回 ThreadLocal 对象实例关联的 value 值(这里使用泛型,所以我们可以为线程保存任意的对象实例),get 方法源代码如下:
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(); }

其中 ThreadLocalMap 为一个自定义的 hashmap 实现(暂时不要关注它的实现细节),其目的是存放键值对 <ThreadLocal,value> 即每个 ThreadLocal 实例关联一个值 value,且线程类 Thread 中声明了一个 ThreadLocalMap 类型属性,用于保存属于该线程的 ‘线程本地变量’。我们知道,对于任一线程,一个 ThreadLocal 对象只关联一个值,而一个线程可以拥有多个 ThreadLocal 实例,所以就可以清晰:每个线程都有一个 hashmap 即 ThreadLocalMap 实例,用来保存属于该线程的 ThreadLocal 实例以及与该 ThreadLocal 实例对应的值 value。注意,每个线程都在一个属于它自己的 hashmap 对象上进行( get/set)操作,所以这里并不会有线程安全问题。当多个线程使用/操作同一个 ThreadLocal 实例时,相当于:有多个 hashmap 实例,使用同一个对象(即 ThreadLocal 实例)作为 key,来关联它们各自的 value 值。

综上,我是为了了解 ThreadLocal 的实现机制,所以从 ThreadLocal 类本身开始下手,但是直到看 ThreadLocalMap 以及线程类 Thread 中的 ThreadLocalMap 类型的属性域,我才恍然大悟:我搞错了顺序,我一开始就进入到了最里面,从而困惑于 ThreadLocal 的实现细节。我认为对 ThreadLocal 的理解,应当从 Thread 类中的 ThreadLocalMap 类型的属性开始:每个线程都有个一 ThreadLocalMap 类型的 hashmap 域,用于维护以 ThreadLocal 对象为 key 并以任意对象为 value 的键值对。所以再看 ThreadLocal,其仅仅用于创建一个普通的对象,该对象没有状态,只是作为 hashmap 的 key 而存在,至于它被多个线程使用,这一点并不特别。(还有一点就是 ThreadLocal 类本身,我认为这个类被设计的比较复杂,因为该类内部还隐藏了其它 3 个类,最关键的就是 ThreadLocalMap 类了,ThreadLocalMap 以它的包装类 ThreadLocal 作为 key,其自身却藏在 ThreadLocal 里面,可见类设计者有意隐藏 ThreadLocal 的实现细节,使得可以像使用普通对象一样对待 ThreadLocal 实例。注意,ThreadLocalMap 虽然定义在 ThreadLocal 的内部,但是它被定义为内部静态类,这和单独定义它其实效果一样,这一点可以简化对 ThreadLocal 的理解。)

转载地址:http://wjlsi.baihongyu.com/

你可能感兴趣的文章
广度优先搜索(BFS)总结及其Java实现
查看>>
非线性数据结构——图的相关概念
查看>>
定位错误日志排查Bug的基本思路大汇总(持续更新)
查看>>
牛客网编程OJ输入输出的加速版(缓冲)
查看>>
整型转化为字符串的Java实现
查看>>
2020.4.8华为笔试二题(Java实现)
查看>>
牛客网编程OJ的典型输入Java模板
查看>>
Leetcode上动态规划系列经典题的Java详解
查看>>
布隆过滤器的介绍
查看>>
Letcode双指针题的Java实现(盛水容器和合并区间)
查看>>
关于比较器Comparable和Comparator
查看>>
BODAS安装的安装与配置
查看>>
BODAS说明书的中文版与相关资料总结
查看>>
关于测控系统的CAN通讯协议总结
查看>>
从SpringMVC源码分析原理
查看>>
《Java编程思想第四版》中在算法题中常用的概念总结(持续更新)
查看>>
git常用工具的原理介绍以及项目使用中常见问题(持续更新)
查看>>
Java性能监控工具Arthas实践
查看>>
Java虚拟机(JVM)调优和Debug的常用参数详解
查看>>
Java内存溢出的典型场景测试
查看>>