官方对ThreadLocal的描述:

  "该类提供了线程局部(thread-local)变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其get或set方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal实例通常是类中的private static字段,它们希望将状态与某一个线程(例如,用户ID或事物ID)相关联。"

《Thinking in Java》中的描述:

  防止任务在共享资源上产生冲突的第二种方式是根除对变量的共享。线程本地存储是一种自动化机制,可以为使用变量的每个不同的线程都创建不同的存储。因此,如果你有5个线程都要使用变量x所表示的对象,那线程本地存储就会生成5个用于x的不同的存储块。主要是,它们使得你可以将状态与线程关联起来。

三个要点:

  1.每个线程都有自己的局部变量

    每个线程都有一个独立于其它线程的上下文来保存这个变量,一个线程的本地变量对其它线程是不可见的。

  2.独立于变量的初始化副本

    ThreadLocal可以给一个初始值,而每个线程都会获得这个初始化值的一个副本,这样才能保证不同的线程都有一份拷贝。

  3.状态与某一个线程相关联

    ThreadLocal不是用于解决共享变量的问题的,不是为了协调线程同步而存在,而是为了方便每个线程处理自己的状态而引入的一个机制,就像《Thinking in Java》中描述的那样:”它们使得你可以将状态与线程关联起来。“理解这点对正确使用ThreadLocal至关重要。

源码举例:

  从输出的结果可以看出,五个线程处理自己的本地变量值。

  而这个测试的结果,并没有相同。这是因为实例为对象,所以初始值为一个对象的引用,那么五个线程的副本就是这个对象的引用的副本,也就是说这些引用还是指向同一个对象,所以就出现了这种情况。

ThreadLocal的接口方法:

  • void set(T value):设置当前线程的线程局部变量的值;
 public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t); if (map != null)
  map.set(this, value);
  //说明线程第一次使用线程本地变量(注意这里的第一次含义)
else
createMap(t, value);
}
  • public T get():该方法返回当前线程所对应的线程局部变量;
 public T get() {
  //获取当前执行线程
  Thread t = Thread.currentThread();
  //取得当前线程的ThreadLocalMap实例
  ThreadLocalMap map = getMap(t);
  //如果map不为空,说明该线程已经有了一个ThreadLocalMap实例
  if (map != null) {
    //map中保存线程的所有的线程本地变量,我们要去查找当前线程本地变量
    ThreadLocalMap.Entry e = map.getEntry(this);
    //如果当前线程本地变量存在这个map中,则返回其对应的值
11     if (e != null)
  return (T)e.value;
13   }
//如果map不存在或者map中不存在当前线程本地变量,返回初始值
return setInitialValue();
}
  • public void remove():将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。当线程结束后,对应该线程的局部变量将被自动垃圾回收,所以显示调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度;
  • protected T initialValue():返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的,这个方法是一个延迟调用方法,在线程第1次调用get()或set(T)时才执行,并且仅执行1次。ThreadLocal中的默认实现直接返回一个null。

这里注意,ThreadLocal中是有一个Map,但这个Map不是我们平时使用的Map,而是ThreadLocalMap,ThreadLocalMap是ThreadLocal的一个内部类,不对外使用的。当使用ThreadLocal存值时,首先是获取到当前线程对象,然后获取到当前线程本地变量Map,最后将当前使用的ThreadLocal和传入的值放到Map中,也就是说ThreadLocalMap中存的值是[ThreadLocal对象, 存放的值]这样做的好处是,每个线程都对应一个本地变量的Map,所以一个线程可以存在多个线程本地变量。下面提供一个简单的实现版本:

Java中ThreadLocal的深入理解的更多相关文章

  1. java中threadlocal的理解

    [TOC] #java中threadlocal的理解##一.threadlocal的生命周期和ThreadLocalMap的生命周期可以吧TreadLocal看做是一个map来使用,只不过这个map是 ...

  2. Java中线程同步的理解 - 其实应该叫做Java线程排队

    Java中线程同步的理解 我们可以在计算机上运行各种计算机软件程序.每一个运行的程序可能包括多个独立运行的线程(Thread). 线程(Thread)是一份独立运行的程序,有自己专用的运行栈.线程有可 ...

  3. java中线程同步的理解(非常通俗易懂)

    转载至:https://blog.csdn.net/u012179540/article/details/40685207 Java中线程同步的理解 我们可以在计算机上运行各种计算机软件程序.每一个运 ...

  4. java中ThreadLocal的使用

    文章目录 在Map中存储用户数据 在ThreadLocal中存储用户数据 java中ThreadLocal的使用 ThreadLocal主要用来为当前线程存储数据,这个数据只有当前线程可以访问. 在定 ...

  5. java中ThreadLocal类的使用

    ThreadLocal是解决线程安全问题一个很好的思路,ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本,由于Key值不可重复, ...

  6. 微冷的雨之Java中的多线程初理解(一)

    在讲解多线程前,我们必须理解什么是多线程?而且很多人都会将进程和线程做对比. 进程和线程 进程:进程是操作系统结构的基础,是一次程序的执行,是一个程序及其数据在处理机上顺序执行时所发生的活动,是程序在 ...

  7. 对Java中字符串的进一步理解

    字符串在程序开发中无处不在,也是用户交互所涉及到最频繁的数据类型,那么字符串不仅仅就是我们简单的理解的String str = "abc";一起来更加深入的看一下 在Java中,字 ...

  8. Java中ThreadLocal的设计与使用

    早在Java 1.2推出之时,Java平台中就引入了一个新的支持:java.lang.ThreadLocal,给我们在编写多线程程序时提供了一种新的选择.使用这个工具类可以很简洁地编写出优美的多线程程 ...

  9. Java学习疑惑(8)----可视化编程, 对Java中事件驱动模型的理解

    我们编写程序就是为了方便用户使用, 我觉得UI设计的核心就是简洁, 操作过于繁琐的程序让很大一部分用户敬而远之. 即使功能强大, 但是人们更愿意使用易于操作的软件. 近年流行起来的操作手势和逐渐趋于成 ...

随机推荐

  1. Gvim for php 安装配置

    VIM for PHP Windows 2011-05-14 11:51:51|  分类: Php|举报|字号 订阅     虽然vim本质上只是一个编辑器.但只要配合一些适当的插件,vim也能变成一 ...

  2. 三、Android NDK编程预备之Java jni入门创建C/C++共享库

    转自: http://www.eoeandroid.com/thread-264971-1-1.html 应网友回复,答应在两天前要出一篇创建C/C++共享库的,但由于清明节假期,跟朋友出去游玩,丢手 ...

  3. C难点分析

    1. 形参和实参 调用函数时,写在括号里面的就是实参,函数本身用的就是形参. 2.字符串问题 char a[5]={"abcd"};注意是4个字符,而不是5个  字符串数组后面带  ...

  4. jQuery年月日(生日)选择器

    我们在编辑用户资料时经常会遇到选择生日选项的问题,今天我给大家介绍如何使用js来实现年月日(生日)选择器,能够准确计算闰年的年月日,方便表单处理. 文章:http://www.helloweba.co ...

  5. jsp中如何用jstl实现if(){}else if(){}else{}

    <c:choose> <c:when test="${条件}"> 情况1........... </c:when> <c:when tes ...

  6. Delphi对于控件的SuperClassing(封装并扩展Button,使之变成TButton)

    写博客写了这么久,但是一直不知道应该怎么样写函数之间的调用关系和执行顺序,因为不停的跳来跳去的,但是写的时候却只能顺序写调用关系,直到今天发现这种写法很不错: TButton创建窗口是在CreateW ...

  7. yii2 增加新的目录结构

    搭建新的目录结构详细点击这里 搭建Restful API 点击这里 1.开发环境操作系统        Windows Server 2012 R2 DatacenterPHP架构        Ap ...

  8. linux 命令案例学习——文件搜索

    两个搜索文件的工具 locate  ——仅仅通过文件名查找文件 find     ——依据文件的各种属性在既定目录(包括子目录)里查找 一个通常与文件搜索命令一起使用.处理搜索结果文件列表的命令 xa ...

  9. B/S和C/S的区别

    B/S 指的是 Browser/Server : C/S 指的是Client/Server 区别: 1. B/S最大优势为客户端免维护,适用于用户群庞大,或客户需求经长发生变化的情况. C/S功能强大 ...

  10. linux fork函数与vfork函数,exit,_exit区别

    man vfork: NAME vfork - create a child process and block parent SYNOPSIS #include <sys/types.h> ...