9-threadLocal
ThreadLocal
多个线程访问同一个共享变量时特别容易出现并发问题,特别是多线程需要对共享变量进行写入时。为了保证线程安全,一般使用者在访问共享变量的时候需要进行适当的同步,如图
同步的一般措施是加锁,这就需要使用者对锁有一定的了解,这显然加重了使用者的负担,那么有没有一种方法可以做到,当创建一个变量后,每个线程对其进行访问的时候访问的是自己线程的变量呢?其实ThreadLocal就可以做到。
ThreadLocal是JDK包提供的,它提供了线程本地变量,也就是说如果创建了一个ThreadLocal变量,那么访问这个变量的每一个线程都会有这个变量的一个本地副本。当多线程操作这个变量的时候,实际操作的就是自己本地内存的里面的里面的变量,从而避免了线程安全问题。创建一个ThreadLocal变量后,每一个线程都会复制一个变量到自己的本地内存。
ThreadLocal使用实例
package com.heiye.learn1; public class ThreadLocalTest {
//print方法
static void print(String threadName) {
//打印当前线程本地内存中LocalVariable变量的值
System.out.println(threadName + ":" + localVariable.get());
//清除当前线程本地内存中的localVariable变量值
//localVariable.remove();
} //创建ThreadLocal变量
static ThreadLocal<String> localVariable = new ThreadLocal<>(); public static void main(String[] args) {
//创建线程threadOne
Thread threadOne = new Thread(new Runnable() {
@Override
public void run() {
//设置线程one变量localVariable值
localVariable.set("threadOne local Variable");
//调用打印函数
print("threadOne");
//打印本地变量值
System.out.println("threadOne remove after" + ":" + localVariable.get());
}
});
//创建线程threadTwo
Thread threadTwo = new Thread(new Runnable() {
@Override
public void run() {
//设置线程two变量localVariable值
localVariable.set("threadTwo local Variable");
//调用打印函数
print("threadTwo");
//打印本地变量值
System.out.println("threadTwo remove after" + ":" + localVariable.get());
}
}); threadOne.start();
threadTwo.start();
}
}

- 线程one首先通过set()方法为threadLocal变量设置了一个值,这其实设置的就是线程one本地内存中对于threadLocal变量的一个副本。这个副本是线程two访问不了的。
如果清除当前线程本地内存中的localVariable变量值,也就是执行localVariable.remove();则:
ThreadLocal实现原理
首先查看一下ThreadLocal类图结构
由该图可知,Thread类有一个ThreadLocals和inheritableThreadLocals,它们都是ThreadLocalMap类型的变量,而ThreadLocalMap是一个定制化的HashMap。在默认的情况下,每个线程中的两个变量都为null,只有当第一个线程调用ThreadLocal的set或者get方法时才会创建它们,其实每个线程得到本地变量不是存放在ThreadLocal实例里面,而是存放在具体的线程内存空间里。ThreadLocal就是一个工具壳,它通过set方法把value值存放在调用线程的threadlocals里面并存放起来,当调用线程调用它的get()方法的时候,再从当前线程的threadLocals变量里面将其拿出来使用。
分析set,get,remove逻辑
//set
public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//将当前线程作为key,到ThreadLocalMap取查找对应的线程变量
ThreadLocalMap map = getMap(t);
//如果找到,则设置
if (map != null)
map.set(this, value);
else //第一次调用就创建当前线程所在的hashmap
createMap(t, 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();
} //remove
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
在每一个线程内都有一个名为threadLocals的成员变量,该变量的类型为HashMap,其中的key为我们定义的threadLocal变量的this引用,value为我们使用set方法设置的值。每个线程的本地变量存放在自己的内存变量ThreadLocals中,如果当前线程一直不消亡,那么这些本地变量会一直存在,所有可能造成内存溢出。
9-threadLocal的更多相关文章
- ThreadLocal简单理解
在java开源项目的代码中看到一个类里ThreadLocal的属性: private static ThreadLocal<Boolean> clientMode = new Thread ...
- Android线程管理之ThreadLocal理解及应用场景
前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...
- Threadlocal使用Case
Threadlocal能够为每个线程分配一份单独的副本,使的线程与线程之间能够独立的访问各自副本.Threadlocal 内部维护一个Map,key为线程的名字,value为对应操作的副本. /** ...
- 多线程映射工具——ThreadLocal
ThreadLocal相当于一个Map<Thread, T>,各线程使用自己的线程对象Thread.currentThread()作为键存取数据,但ThreadLocal实际上是一个包装了 ...
- ThreadLocal 工作原理、部分源码分析
1.大概去哪里看 ThreadLocal 其根本实现方法,是在Thread里面,有一个ThreadLocal.ThreadLocalMap属性 ThreadLocal.ThreadLocalMap t ...
- ThreadLocal<T>的是否有设计问题
一.吐槽 ThreadLocal<T>明显是.NET从JAVA中来的一个概念,但是这种设计是否出现了问题. 很明显,在JAVA中threadLocal直接是Thread的成员,当然随着th ...
- 理解ThreadLocal —— 一个map的key
作用: 当工作于多线程中的对象使用ThreadLocal维护变量时,threadLocal为每个使用该变量的线程分配一个独立的变量副本. 接口方法: protected T initialValue( ...
- JavaSe:ThreadLocal
JDK中有一个ThreadLocal类,使用很方便,但是却很容易出现问题.究其原因, 就是对ThreadLocal理解不到位.最近项目中,出现了内存泄漏的问题.其中就有同事在使用ThreadLocal ...
- 0041 Java学习笔记-多线程-线程池、ForkJoinPool、ThreadLocal
什么是线程池 创建线程,因为涉及到跟操作系统交互,比较耗费资源.如果要创建大量的线程,而每个线程的生存期又很短,这时候就应该使用线程池了,就像数据库的连接池一样,预先开启一定数量的线程,有任务了就将任 ...
- ThreadLocal 源码剖析
ThreadLocal是Java语言提供的用于支持线程局部变量的类.所谓的线程局部变量,就是仅仅只能被本线程访问,不能在线程之间进行共享访问的变量(每个线程一个拷贝).在各个Java web的各种框架 ...
随机推荐
- C#设计模式---PipeLine
一.概述 顾名思义,管道模式就像一条管道把多个对象连接起来,整体看起来就像若干个阀门嵌套在管道中,而处理逻辑就放在阀门上,如下图,需要处理的对象进入管道后,分别经过阀门一.阀门二.阀门三.阀门四,每个 ...
- C#多线程---委托实现异步
一.概述 通过调用ThreadPool的QueueUserWorkItem方法来来启动工作者线程非常方便,但委托WaitCallback指向的是带有一个参数的无返回值的方法. 如果我们实际操作中需要有 ...
- Hibernate的一级缓存和二级缓存
Fist level cache: This is enabled by default and works in session scope. Read more about hibernate f ...
- 客户机与服务器TCP连接状态
客户机:
- 由struts2中配置使用servlet引发的思考和复习
Struts2拦截器到底拦截了什么? 关于struts2中的拦截器,首先再次理解其实只能过滤其中访问的action的映射!再者,因为struts中的action其实就是起到替代servlet作用的,所 ...
- 微信小程序学习笔记四 自定义组件
1. 自定义组件 类似Vue或react中的自定义组件 小程序允许我们使用自定义组件的方式来构建页面 1.1 创建自定义组件 类似于页面, 一个自定义组件由json wxml wxss js 4个文件 ...
- Web应用安全防护-WAF
web应用开发中不可避免需要考虑web应用的安全问题,那么常见的安全风险包含哪些呢? Web应用常见的安全风险 在web应用开发中可能存在以下的安全风险: 安全风险Top 10 A1:2017-注入 ...
- Python中的文件处理和数据存储json
前言:每当需要分析或修改存储在文件中的信息时,读取文件都很有用,对数据分析应用程序来说尤其如此. 例如,你可以编写一个这样的程序:读取一个文本文件的内容,重新设置这些数据的格式并将其写入文件,让浏览器 ...
- zap高性能日志
摘要 日志在整个工程实践中的重要性不言而喻,在选择日志组件的时候也有多方面的考量.详细.正确和及时的反馈是必不可少的,但是整个性能表现是否也是必要考虑的点呢?在长期的实践中发现有的日志组件对于计算资源 ...
- eBPF 安全项目 Tracee 初探
1. Tracee 介绍 1.1 Tracee 介绍 Tracee 是一个用 于 Linux 的运行时安全和取证工具.它使用 Linux eBPF 技术在运行时跟踪系统和应用程序,并分析收集的事件以检 ...



