线程局部变量 ThreadLocal
文章目录
- 线程局部变量 ThreadLocal
- ThreadLocal 的作用和目的
- ThreadLocal 的应用场景
- ThreadLocal 的使用方式
- (1) 在关联数据类中创建 private static ThreadLocal
- 2. 在 Util 类中创建 ThreadLocal
- 3. 在 Runnable 中创建 ThreadLocal
线程局部变量 ThreadLocal
ThreadLocal 的作用和目的
- 用于实现线程内的数据共享,即对于相同的程序代码,多个模块在同一个 线程中运行时要共享一份数据,而在另外线程中运行时又共享另外一份数据。
- 每个线程调用全局 ThreadLocal 对象的 set 方法,在 set 方法中,首先根据当前线程获取当前线程的
ThreadLocalMap 对象,然后往这个 map 中插入一条记录,key 其实是 ThreadLocal 对象,value 是各自的 set方法传进去的值。也就是每个线程其实都有一份自己独享的 ThreadLocalMap对象,该对象的 Key 是 ThreadLocal对象,值是用户设置的具体值。在线程结束时可以调用 ThreadLocal.remove()方法,这样会更快释放内存,不调用也可以,因为线程结束后也可以自动释放相关的 ThreadLocal 变量。
ThreadLocal 的应用场景
订单处理包含一系列操作:减少库存量、增加一条流水台账、修改总账,这几个操作要在同一个
事务中完成,通常也即同一个线程中进行处理,如果累加公司应收款的操作失败了,则应该把前面
的操作回滚,否则,提交所有操作,这要求这些操作使用相同的数据库连接对象,而这些操作的代码 分别位于不同的模块类中。银行转账包含一系列操作: 把转出帐户的余额减少,把转入帐户的余额增加,这两个操作要在同一个事务中完成,它们必须使用相同的数据库连接对象,转入和转出操作的代码分别是两个不同 的帐户对象的方法。
例如 Strut2 的 ActionContext,同一段代码被不同的线程调用运行时,该代码操作的数据是每个线程各自的状态和数据,对于不同的线程来说,getContext 方法拿到的对象都不相同,对同一个 线程来说,不管调用 getContext 方法多少次和在哪个模块中 getContext 方法,拿到的都是同一 个。
ThreadLocal 的使用方式
(1) 在关联数据类中创建 private static ThreadLocal
在下面的类中,私有静态 ThreadLocal 实例(serialNum)为调用该类的静态 SerialNum.get() 方法的每个线程维护了一个“序列号”,该方法将返回当前线程的序列号。(线程的序列号是在第一次调用 SerialNum.get() 时分配的,并在后续调用中不会更改。)
package com.wjl.test.mythreadLocal;public class SerialNum {//The next serial number to be assignedprivate static int nextSerialNum=0;private static ThreadLocal serialNum=new ThreadLocal(){protected synchronized Object initialValue(){return new Integer(nextSerialNum++);}};public static int get(){return ((Integer)(serialNum.get())).intValue();}public static void main(String[] args) {System.out.println(get());//0new Thread(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"serialNum = "+get());}}).start(); //1}
}
另一个例子,也是私有静态 ThreadLocal 实例:
package com.wjl.test.mythreadLocal;import java.util.Random;public class ThreadContext {private String userId;private Long transactionId;private static ThreadLocal threadLocal=new ThreadLocal(){@Overrideprotected Object initialValue() {// return super.initialValue();return new ThreadContext();}};public static ThreadContext get(){return (ThreadContext) threadLocal.get();}public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}public Long getTransactionId() {return transactionId;}public void setTransactionId(Long transactionId) {this.transactionId = transactionId;}@Overridepublic String toString() {return "ThreadContext{" +"userId='" + userId + '\'' +", transactionId=" + transactionId +'}';}public static void main(String[] args) {for (int i=0;i < 10; i++) {new Thread(new Runnable() {@Overridepublic void run() {ThreadContext threadContext=ThreadContext.get();threadContext.setUserId( new Random().nextInt(100) +"");threadContext.setTransactionId(new Random().nextLong());System.out.println("Thread name:"+Thread.currentThread().getName() +","+threadContext);}}).start();}}
}
2. 在 Util 类中创建 ThreadLocal
import sun.rmi.runtime.Log;import javax.security.auth.login.Configuration;public class HibernateUtil {private static Log log = LogFactory.getLog(HibernateUtil.class);private static final SessionFactory sessionFactory; //定义 SessionFactorystatic {try {// 通过默认配置文件 hibernate.cfg.xml 创建 SessionFactorysessionFactory = new Configuration().configure().buildSessionFactory();} catch (Throwable ex) {log.error("初始化 SessionFactory 失败!", ex);throw new ExceptionInInitializerError(ex);}}//创建线程局部变量 session,用来保存 Hibernate 的 Sessionpublic static final ThreadLocal session = new ThreadLocal();/*** 获取当前线程中的 Session** @return Session* @throws HibernateException*/public static Session currentSession() throws HibernateException {Session s = (Session) session.get();// 如果 Session 还没有打开,则新开一个 Sessionif (s == null) {s = sessionFactory.openSession();session.set(s); //将新开的 Session 保存到线程局部变量中}return s;}public static void closeSession() throws HibernateException {//获取线程局部变量,并强制转换为 Session 类型Session s = (Session) session.get();session.set(null);if (s != null)s.close();}
}
3. 在 Runnable 中创建 ThreadLocal
在线程类内部创建 ThreadLocal,基本步骤如下:
- ①、在多线程的类(如 ThreadDemo 类)中,创建一个 ThreadLocal 对象 threadXxx,用来保存线程间需要隔离处理的对象 xxx。
- ②、在 ThreadDemo 类中,创建一个获取要隔离访问的数据的方法 getXxx(),在方法中判断,若ThreadLocal 对象为 null 时候,应该 new()一个隔离访问类型的对象,并强制转换为要应用的类型
- ③、在 ThreadDemo 类的 run()方法中,通过调用 getXxx()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象。
package com.wjl.test.mythreadLocal;import java.util.Random;public class ThreadLocalTest implements Runnable {ThreadLocal<Student> studenThreadLocal = new ThreadLocal<Student>();@Overridepublic void run() {String currentThreadName = Thread.currentThread().getName();System.out.println(currentThreadName + " si running...");Random random = new Random();int age = random.nextInt(100);System.out.println(currentThreadName + " is set age : " + age);//通过这个方法,为每个线程都独立的 new 一个 student 对象,// 每个线程的的student 对象都可以设置不同的值Student student = getStudent();student.setAge(age);System.out.println(currentThreadName + " is first get age: " + student.getAge());try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(currentThreadName + " is second get age:" + student.getAge());}public static void main(String[] args) {ThreadLocalTest t = new ThreadLocalTest();Thread t1 = new Thread(t, "Thread A");Thread t2 = new Thread(t, "Thread B");t1.start();t2.start();}private Student getStudent() {Student student = studenThreadLocal.get();if (null == student) {student = new Student();studenThreadLocal.set(student);}return student;}
}class Student {int age;public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
线程局部变量 ThreadLocal相关推荐
- Java线程局部变量ThreadLocal
ThreadLocal基础 ThreadLocal类可以让每个线程绑定自己的值,它就像一个全局存放数据的盒子,盒子中可以存放每个线程的私有数据. ThreadLocal类只有一个无参的构造函数,因此实 ...
- 线程知识-ThreadLocal使用详解
最近在看Spring的时候回顾了一下ThreadLocal,下面是ThreadLocal的使用说明. 概述 首先,谈到ThreadLocal的使用,我们先来了解一下ThreadLocal是什么?Thr ...
- 线程本地ThreadLocal的介绍与使用!
ThreadLocal简介 我们通过上两篇的学习,我们已经知道了变量值的共享可以使用public static变量的形式,所有的线程都使用同一个被public static修饰的变量. 那么如果我们想 ...
- Java小白的入门面试笔记--线程局部变量之灵魂四问
1.ThreadLocal 是什么? ThreadLocal俗名叫做线程局部变量,就是由ThreadLocal通过set方法填充的变量,它是只属于当前的线程,对于其他的线程来说是隔离的,是当前线程独有 ...
- 获取父线程 java_java子线程中获取父线程的threadLocal中的值
我们都知道线程本地变量表也就是ThreadLocal在我们做线程级的数据隔离时非常好用,但是有时候我们会想如何让子线程获取到父线程的ThreadLocal,其实在线程中除了ThreadLocal外还有 ...
- java线程间ThreadLocal的传递
文章目录 1 场景 2 需确认问题 2.1 继承线程的ThreadLocal的含义 2.2 子线程内的ThreadLocal的值和父线程内的有什么关系? 2.3 父线程内的ThreadLocal清除后 ...
- 线程的局部变量ThreadLocal概念
ThreadLocal是什么 对这个词语分解,将其分为Thread和Local,顾名思义便是本线程的变量,既然是当前线程的变量,那么就意味着这个变量对于其他线程来说就是隔离的,也就是不可见的,Thre ...
- Java 并发编程之 ThreadLocal 线程局部变量
ThreadLocal 通过get和set方法,为每个使用该变量的线程提供一个独立的副本,使得线程安全的共享某个变量:使用 set 方法设置变量后,一定要记得及时使用 remove 方法清理,否则多线 ...
- 重点知识学习(8.4)--[线程池 , ThreadLocal]
文章目录 1.线程池 线程池构造函数中的7个参数 线程池的执行过程 线程的执行工作队列 execute 与 submit 的区别 线程池拒绝策略 关闭线程池方法 shutdownNow 和 shutd ...
最新文章
- java regexp_java中使用regexp
- Angular使用@Input和@Output实现父子组件互相传参(类似Vue的props和this.emit)
- 小程序订阅消息 订阅消息开发
- 彻底解决web开发中遇到的路径问题(上)
- 染成茜色的坂道 汉化版攻略
- C++ Primer 5th笔记(chap 17 标准库特殊设施)正则表达式类和输入序列类型
- mojoportal学习——文章翻译之多行横排菜单
- Find All Numbers Disappeared in an Array
- [react] react中的setState和replaceState的区别是什么?
- 将不确定变为确定~一切归总为“二”(C#中的位运算有啥用)
- jmeter+ant+jenkins接口自动环境搭建
- 在Idea2017.1中编译时发生如下的错误
- 大型网站技术架构演进与性能优化
- 对数回归 matlab,高斯过程回归GPR-MATLAB语法解释
- java p2p 聊天_P2P--多用户在线聊天室(Java源码)
- 计算机考研复试面试题专业知识整理
- 表格与合并之Excel如何快速合并多个表格数据
- Service层在分层中的作用
- java基础知识学习小总结(一)
- C语言中#和##的作用
热门文章
- Android录制或播放语音消息时关闭其他媒体播放
- 关于input框的兼容性问题
- 【物联网项目系列】springboot 实现mqtt物联网
- 线上打印马上送,支持线上打印文档的软件
- 华为鸿蒙系统智能手机_Android再见!华为42款智能手机将兼容鸿蒙操作系统
- Stardock Curtains v1.19.1 Windows主题美化软件中文直装版
- [蓝桥杯][历届试题 PREV-50]对局匹配(Java)(动态规划)
- JQuery 向下展开收起动画( slideDown(),slideUp() )
- 遇到jQuery 中的 slideUp ,slideToggle和 slideDown 动画重复执行
- 芯片失效分析手段系列之X-RAY探伤