Java ThreadLocal 理解
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 理解的更多相关文章
- java ThreadLocal理解和使用
一.ThreadLoal的理解 ThreadLoal 变量,它的基本原理是,同一个 ThreadLocal 所包含的对象(对ThreadLocal< String >而言即为 String ...
- Android线程管理之ThreadLocal理解及应用场景
前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...
- Java ThreadLocal 源代码分析
Java ThreadLocal 之前在写SSM项目的时候使用过一个叫PageHelper的插件 可以自动完成分页而不用手动写SQL limit 用起来大概是这样的 最开始的时候觉得很困惑,因为直接使 ...
- [java] 深入理解内部类: inner-classes
[java] 深入理解内部类: inner-classes // */ // ]]> [java] 深入理解内部类: inner-classes Table of Contents 1 简介 ...
- Java初始化理解与总结 转载
Java的初始化可以分为两个部分: (a)类的初始化 (b)对象的创建 一.类的初始化 1.1 概念介绍: 一个类(class)要被使用必须经过装载,连接,初始化这样的过程. 在装载阶段,类装载器会把 ...
- 从Java视角理解CPU上下文切换(Context Switch)
从Java视角理解系统结构连载, 关注我的微博(链接)了解最新动态 在高性能编程时,经常接触到多线程. 起初我们的理解是, 多个线程并行地执行总比单个线程要快, 就像多个人一起干活总比一个人干要快 ...
- 从Java视角理解CPU缓存(CPU Cache)
从Java视角理解系统结构连载, 关注我的微博(链接)了解最新动态众所周知, CPU是计算机的大脑, 它负责执行程序的指令; 内存负责存数据, 包括程序自身数据. 同样大家都知道, 内存比CPU慢很多 ...
- Java IO 理解流的概念
Java IO 理解流的概念 @author ixenos 在理解流时首先理解以下概念 1.流的来源和去向一般在构造器指出 2.方法中的形参一般是将流输出到某个位置,读取(INPUT)流从流读出数据( ...
- Effective Java通俗理解(持续更新)
这篇博客是Java经典书籍<Effective Java(第二版)>的读书笔记,此书共有78条关于编写高质量Java代码的建议,我会试着逐一对其进行更为通俗易懂地讲解,故此篇博客的更新大约 ...
随机推荐
- ASP.NET 文件操作类
1.读取文件 2.写入文件 using System; using System.Collections.Generic; using System.IO; using System.Linq; us ...
- MySQL(十)操纵表及全文本搜索
一.创建表 MySQL不仅用于表数据操作,还可以用来执行数据库和表的所有操作,包括表本身的创建和处理. 创建表一般有如下两种方式: ①使用具有交互式创建和管理表的工具: ②直接使用MySQL语句操纵表 ...
- 学习CSS布局 - position
position 为了制作更多复杂的布局,我们需要讨论下 position 属性. 它有一大堆的值,名字还都特抽象,别提有多难记了. 让我们先一个个的过一遍,不过你最好还是把这页放到书签里. 先看下运 ...
- kubernetes 持久化部署lamp类型网站
1.构建mariadb的镜像 cat Dockerfile FROM mariadb:latest ADD twocloud_kk.sql /docker-entrypoint-initdb.d #C ...
- BZOJ 2784 时间流逝
BZOJ 2784 时间流逝 古典概率论... 可以发现由于能量圈数量限制,所以所构成的必定为树状结构(即便是转成最小能量圈和能量圈权值和之后存在重复状态,但是每个状态的含义不同,而且不能自身转移自身 ...
- Codeforces round 1083
Div1 526 这个E考试的时候没调出来真的是耻辱.jpg A 求个直径就完事 #include<cstdio> #include<algorithm> #include&l ...
- React-页面路由参数传递的两种方法
list页->detail页 方法一:路由参数 路由导航: 用“/” <Link to={'/detail/'+item.get('id')} key={index}> 路由map: ...
- Python从菜鸟到高手(2):清空Python控制台
执行python命令会进入Python控制台.在Python控制台中可以用交互的方式执行Python语句.也就是执行一行Python语句,会立刻返回执行结果. 当Python控制台输入过多的Pyt ...
- item 1:理解template类型的推导
本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 一些用户对复杂的系统会忽略它怎么工作,怎么设计的,但是很高兴去知道它完成的一些事.通过这 ...
- 【转】Git版本控制软件从入门到精通学习手册
GIT 学习手册简介 本站为 Git 学习参考手册.目的是为学习与记忆 Git 使用中最重要.最普遍的命令提供快速翻阅. 这些命令以你可能需要的操作类型划分,并且将提供日常使用中需要的一些常用的命令以 ...