文章目录

  • 线程局部变量 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相关推荐

  1. Java线程局部变量ThreadLocal

    ThreadLocal基础 ThreadLocal类可以让每个线程绑定自己的值,它就像一个全局存放数据的盒子,盒子中可以存放每个线程的私有数据. ThreadLocal类只有一个无参的构造函数,因此实 ...

  2. 线程知识-ThreadLocal使用详解

    最近在看Spring的时候回顾了一下ThreadLocal,下面是ThreadLocal的使用说明. 概述 首先,谈到ThreadLocal的使用,我们先来了解一下ThreadLocal是什么?Thr ...

  3. 线程本地ThreadLocal的介绍与使用!

    ThreadLocal简介 我们通过上两篇的学习,我们已经知道了变量值的共享可以使用public static变量的形式,所有的线程都使用同一个被public static修饰的变量. 那么如果我们想 ...

  4. Java小白的入门面试笔记--线程局部变量之灵魂四问

    1.ThreadLocal 是什么? ThreadLocal俗名叫做线程局部变量,就是由ThreadLocal通过set方法填充的变量,它是只属于当前的线程,对于其他的线程来说是隔离的,是当前线程独有 ...

  5. 获取父线程 java_java子线程中获取父线程的threadLocal中的值

    我们都知道线程本地变量表也就是ThreadLocal在我们做线程级的数据隔离时非常好用,但是有时候我们会想如何让子线程获取到父线程的ThreadLocal,其实在线程中除了ThreadLocal外还有 ...

  6. java线程间ThreadLocal的传递

    文章目录 1 场景 2 需确认问题 2.1 继承线程的ThreadLocal的含义 2.2 子线程内的ThreadLocal的值和父线程内的有什么关系? 2.3 父线程内的ThreadLocal清除后 ...

  7. 线程的局部变量ThreadLocal概念

    ThreadLocal是什么 对这个词语分解,将其分为Thread和Local,顾名思义便是本线程的变量,既然是当前线程的变量,那么就意味着这个变量对于其他线程来说就是隔离的,也就是不可见的,Thre ...

  8. Java 并发编程之 ThreadLocal 线程局部变量

    ThreadLocal 通过get和set方法,为每个使用该变量的线程提供一个独立的副本,使得线程安全的共享某个变量:使用 set 方法设置变量后,一定要记得及时使用 remove 方法清理,否则多线 ...

  9. 重点知识学习(8.4)--[线程池 , ThreadLocal]

    文章目录 1.线程池 线程池构造函数中的7个参数 线程池的执行过程 线程的执行工作队列 execute 与 submit 的区别 线程池拒绝策略 关闭线程池方法 shutdownNow 和 shutd ...

最新文章

  1. java regexp_java中使用regexp
  2. Angular使用@Input和@Output实现父子组件互相传参(类似Vue的props和this.emit)
  3. 小程序订阅消息 订阅消息开发
  4. 彻底解决web开发中遇到的路径问题(上)
  5. 染成茜色的坂道 汉化版攻略
  6. C++ Primer 5th笔记(chap 17 标准库特殊设施)正则表达式类和输入序列类型
  7. mojoportal学习——文章翻译之多行横排菜单
  8. Find All Numbers Disappeared in an Array
  9. [react] react中的setState和replaceState的区别是什么?
  10. 将不确定变为确定~一切归总为“二”(C#中的位运算有啥用)
  11. jmeter+ant+jenkins接口自动环境搭建
  12. 在Idea2017.1中编译时发生如下的错误
  13. 大型网站技术架构演进与性能优化
  14. 对数回归 matlab,高斯过程回归GPR-MATLAB语法解释
  15. java p2p 聊天_P2P--多用户在线聊天室(Java源码)
  16. 计算机考研复试面试题专业知识整理
  17. 表格与合并之Excel如何快速合并多个表格数据
  18. Service层在分层中的作用
  19. java基础知识学习小总结(一)
  20. C语言中#和##的作用

热门文章

  1. Android录制或播放语音消息时关闭其他媒体播放
  2. 关于input框的兼容性问题
  3. 【物联网项目系列】springboot 实现mqtt物联网
  4. 线上打印马上送,支持线上打印文档的软件
  5. 华为鸿蒙系统智能手机_Android再见!华为42款智能手机将兼容鸿蒙操作系统
  6. Stardock Curtains v1.19.1 Windows主题美化软件中文直装版
  7. [蓝桥杯][历届试题 PREV-50]对局匹配(Java)(动态规划)
  8. JQuery 向下展开收起动画( slideDown(),slideUp() )
  9. 遇到jQuery 中的 slideUp ,slideToggle和 slideDown 动画重复执行
  10. 芯片失效分析手段系列之X-RAY探伤