ThreadLocal 概念:

ThreadLocal不是用来解决对象共享访问的问题,而主要是提供了保存对象的方法和避免参数传递的方便的对象访问方式。

ThreadLocal并不是一个Thread,而是Thread的局部变量,当使用ThreadLocal维护变量的时候ThreadLocal为每一个使用该变量的线程提供了独立的变量副本,也就是说每一个线程都可以单独改变自己的副本,而不会影响其他线程的副本。

从线程的角度来看目标变量就是当前线程的本地变量,这也就是类名Local的含义。

ThreadLocal的4个方法:

  void set(T value)  将此线程局部变量的当前线程副本中的值设置为指定值

  void remove()  移除此线程局部变量当前线程的值

  protected T initialValue()  返回此线程局部变量的当前线程的初始值

  T get()  返回此线程局部变量的当前线程副本中的值

注意 :默认情况下 initValue(), 返回 null 。线程在没有调用 set 之前,第一次调用 get 的时候, get方法会默认去调用 initValue 这个方法。所以如果没有覆写这个方法,可能导致 get 返回的是 null 。当然如果调用过 set 就不会有这种情况了。但是往往在多线程情况下我们不能保证每个线程的在调用 get 之前都调用了set ,所以最好对 initValue 进行覆写,以免导致空指针异常。

ThreadLocal实现原理:

ThreadLocal是如何做到为每一个线程维护变量的副本呢?让我们来看看ThreadLocal的源码:

public class ThreadLocal<T> {

    public T get() {
// 获取当前线程
Thread t = Thread.currentThread();
// 获取当前线程的threadLocals变量
ThreadLocalMap map = getMap(t);
// 从当前线程的threadLocals变量中取得本threadLocal为key的值
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T) e.value;
}
return setInitialValue();
} private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
} public void set(T value) {
// 获取当前线程
Thread t = Thread.currentThread();
// 获取当前线程的threadLocals变量
ThreadLocalMap map = getMap(t);
// 以本threadLocal为key的保存值到当前线程的threadLocals变量中去
if (map != null)
map.set(this, value);
else
createMap(t, value);
} ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
} void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
}

在ThreadLocal类中有一个map,用于存储没一个线程的变量副本,map中的元素key为线程对象 value为线程副本中的变量值

示例:

package cn.com.example;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* Created by Jack on 2017/2/13.
*/
public class ThreadLocalTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 3; i++) {
executorService.execute(new ThreadTest());
} executorService.shutdownNow();
}
} class ThreadTest implements Runnable { @Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " value=" + ThreadLocalNumber.get());
}
}
} class ThreadLocalNumber {
private static ThreadLocal<Integer> value = new ThreadLocal<Integer>() {
protected synchronized Integer initialValue() {
return 0;
}
}; public static void set() {
value.set(value.get() + 1);
} public static int get() {
// 为了测试 直接在get里面 ++
value.set(value.get() + 1);
return value.get();
}
}

结果:

pool-1-thread-3 value=1
pool-1-thread-2 value=1
pool-1-thread-1 value=1
pool-1-thread-2 value=2
pool-1-thread-3 value=2
pool-1-thread-2 value=3
pool-1-thread-1 value=2
pool-1-thread-2 value=4
pool-1-thread-2 value=5
pool-1-thread-3 value=3
pool-1-thread-3 value=4
pool-1-thread-3 value=5
pool-1-thread-1 value=3
pool-1-thread-1 value=4
pool-1-thread-1 value=5

从运行结果得知 各线程都用于各自的Local变量,并各自读写互不干扰。

Java ThreadLocal 理解的更多相关文章

  1. java ThreadLocal理解和使用

    一.ThreadLoal的理解 ThreadLoal 变量,它的基本原理是,同一个 ThreadLocal 所包含的对象(对ThreadLocal< String >而言即为 String ...

  2. Android线程管理之ThreadLocal理解及应用场景

    前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...

  3. Java ThreadLocal 源代码分析

    Java ThreadLocal 之前在写SSM项目的时候使用过一个叫PageHelper的插件 可以自动完成分页而不用手动写SQL limit 用起来大概是这样的 最开始的时候觉得很困惑,因为直接使 ...

  4. [java] 深入理解内部类: inner-classes

    [java] 深入理解内部类: inner-classes // */ // ]]>   [java] 深入理解内部类: inner-classes Table of Contents 1 简介 ...

  5. Java初始化理解与总结 转载

    Java的初始化可以分为两个部分: (a)类的初始化 (b)对象的创建 一.类的初始化 1.1 概念介绍: 一个类(class)要被使用必须经过装载,连接,初始化这样的过程. 在装载阶段,类装载器会把 ...

  6. 从Java视角理解CPU上下文切换(Context Switch)

    从Java视角理解系统结构连载, 关注我的微博(链接)了解最新动态   在高性能编程时,经常接触到多线程. 起初我们的理解是, 多个线程并行地执行总比单个线程要快, 就像多个人一起干活总比一个人干要快 ...

  7. 从Java视角理解CPU缓存(CPU Cache)

    从Java视角理解系统结构连载, 关注我的微博(链接)了解最新动态众所周知, CPU是计算机的大脑, 它负责执行程序的指令; 内存负责存数据, 包括程序自身数据. 同样大家都知道, 内存比CPU慢很多 ...

  8. Java IO 理解流的概念

    Java IO 理解流的概念 @author ixenos 在理解流时首先理解以下概念 1.流的来源和去向一般在构造器指出 2.方法中的形参一般是将流输出到某个位置,读取(INPUT)流从流读出数据( ...

  9. Effective Java通俗理解(持续更新)

    这篇博客是Java经典书籍<Effective Java(第二版)>的读书笔记,此书共有78条关于编写高质量Java代码的建议,我会试着逐一对其进行更为通俗易懂地讲解,故此篇博客的更新大约 ...

随机推荐

  1. sd错误---2

    一道水题 绊了我,居然 愿意很简单 我多打了一遍int main 阴错阳差的 自定义的函数上面 出现了int main 所以 以后想想好思路(是那种很全很全的思路) 再写代码 一定要避免sd错误!!! ...

  2. VUE2第五天学习---自定义指令

    阅读目录 1.理解VUE中的自定义指令 回到顶部 1.理解VUE中的自定义指令 默认核心指令有 (v-model 和 v-show), 但是有时候我们需要用到自定义指令,在vue中,代码复用主要形式和 ...

  3. MVC 5限制所有HTTP请求必须是POST方式

    今天有位同事,提出了这样一个问题,他想限制所有MVC接收到的HTTP请求必须是POST方式. 接下来在下面的内容中,将我想到的方式分享给大家,如果大家有其它的方式,请留言. 一.HttpPostAtt ...

  4. 读《Top benefits of continuous integration》有感

    看到一片文章<Top benefits of continuous integration>,这张图画的很棒.将整个CI流程各阶段,列举出来了. 作者在文章里面介绍了CI和TDD,以及采用 ...

  5. decorator, async/await, generator

    ////////////decorator////////// function aopFunc (target, key, descriptor) { console.log('aopFunc') ...

  6. OLED小记

    1.点阵组成OLED,OLED中有一个GRAM区域,区域中的值直接刷新到屏幕上,对应关系是1bit对应一个像素点: 2.要点亮一个像素点,只需要将GRAM中的对应bit位写1即可.GRAM中是分页来管 ...

  7. Jlink使用技巧之烧写SPI Flash存储芯片

    前言 大多数玩单片机的人都知道Jlink可以烧写Hex文件,作为ARM仿真调试器,但是知道能烧写SPI Flash的人应该不多,本篇文章将介绍如何使用JLink来烧写或者读取SPI Flash存储器, ...

  8. 扫描shader

    游戏中经常需要制作出白光扫描的效果,这道光在透明区域不会显示.如果用图片叠加可能透明区域不太好处理,这里可通过shader实现. Shader "Custom/LogoShader" ...

  9. 【nodejs】让nodejs像后端mvc框架(asp.net mvc)一orm篇【如EF般丝滑】typeorm介绍(8/8)

    文章目录 前情概要 在使用nodejs开发过程中,刚好碰到需要做一个小工具,需要用到数据库存储功能.而我又比较懒,一个小功能不想搞一个nodejs项目,又搞一个后端项目.不如直接在nodejs里面把对 ...

  10. 2018年计划小里程碑(6月)PMI-ACP 敏捷

    年初定的计划之一,考证... 7A,意料之外,也是意料之中.历时两个月多,2018.3.31号决定报名,顶着压报了ACP+ACP实战+PMP,考虑了下敏捷是未来项目管理的趋势,大部分公司正在向敏捷转型 ...