Java中java.lang.ThreadLocal类不是一个线程的本地实现,而是线程局部变量,也许叫ThreadlocalVar更加合适。ThreaLocal使用非常简单,就是为使用该变量的线程提供一个变量值的副本,每个线程都可以独立的改变自己的副本,而不会与其他线程冲突。
从线程角度看,每个线程都保持一个对其线程局部变量的隐式引用,只要线程是活动并且ThreadLocal实例可访问。线程结束之后,相应的线程局部变量的所有副本都会被垃圾回收。
通过ThreadLocal存取的数据,总是与当前线程有关。Jvm为每个运行的线程,绑定了私有的本地实例存取空间,每一个线程都可以独立地改变空间内容而不会和其他线程副本冲突,从而隔离了线程,解决的并发访问问题。
ThreadLocal的实现思路很简单,在其内部有一个Map,用户存储每一个线程变量副本。
对已多线程资源共享问题,有两种解决方式,一种同步机制,以时间换空间,不同的线程排队访问。一种是ThreadLocal,以空间换时间,为每个线程都复制一份共享资源的副本,线程直接访问自己的副本,因此可以同时访问互不影响。
ThreadLocal主要由四个方法组成initialValue(),get(),set(T),remove(),其中值得注意的是initialVlaue(),该方法是一个protected的方法,显然是为了子类重写而特意实现的。该方法返回当前线程在该线程局部变量的初十值。这是方法是一个延时调用的方法,在一个线程第一次调用get()或者set(object )时才执行,丙炔仅执行1次。ThreadLocal中确实实现直接返回一个null;
使用ThreadLocal的典型实例就是Hibernate中的session工具类HibernateUtil,该类用于session管理。
public class HibernateUtil {
private static Log log = LogFactory.getLog(HibernateUtil.class);
private static final SessionFactory sessionFactory; //定义SessionFactory
static {
try {
// 通过默认配置文件hibernate.cfg.xml创建SessionFactory
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
log.error("初始化SessionFactory失败!", ex);
throw new ExceptionInInitializerError(ex);
}
}
//创建线程局部变量session,用来保存Hibernate的Session
public static final ThreadLocal session = new ThreadLocal();
/**
* 获取当前线程中的Session
* @return Session
* @throws HibernateException
*/
public static Session currentSession() throws HibernateException {
Session s = (Session) session.get();
// 如果Session还没有打开,则新开一个Session
if (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();
}
}
在这个类中,由于没有重写ThreadLocal的initialValue()方法,则首次创建线程局部变量session的初始值为null,第一次调用currentSesion()的时候,线程局部变量的get()方法也为null。因此,对session做判断,如果为null,则打开一个新的会话,并保存线程局部变量session中,这一步非常关键,这也是“public static final ThreadLocal seesion = new ThreadLocal()”所创建对象session能强制转换为Hibernate
Session对象的原因。
ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。
下面是自己写的一个小例子,创建一个Bean,通过不同的线程对象设置Bean属性,保证各个线程Bean对象的独立性。
public class Bean {
private int num;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
public class ThreadLocalDemo implements Runnable {
//创建线程局部变量,用来保存bean
private static final ThreadLocal<Bean> beanLocal = new ThreadLocal<Bean>();
public Bean getBean(){
//获取线程本地变量
Bean bean = beanLocal.get();
//如何还没有设置,则设置。(第一次肯定为空)
if(bean==null){
//将新建的bean保存到线程本地变量
bean = new Bean();
beanLocal.set(bean);
}
return bean;
}
public void test(){
//获取当前线程名字
String threadName = Thread.currentThread().getName();
System.out.println("currThreadName:"+threadName);
//生成随机数
Random random = new Random();
int num = random.nextInt(10);
//获取当前线程本地变量bean,并将num设置到bean变量中
Bean bean = getBean();
bean.setNum(num);
System.out.println("threadName"+threadName+",BeanInt:"+num);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("currThreadName:"+threadName+", currrThreadBeanName:"+bean.getNum());
}
@Override
public void run() {
test();
}
public static void main(String[] args){
ThreadLocalDemo demo = new ThreadLocalDemo();
Thread td1 = new Thread(demo,"demo1");
Thread td2 = new Thread(demo,"demo2");
td1.start();
td2.start();
}
}
分享到:
相关推荐
- `HttpClient学习笔记.doc`: 可能包含了关于Apache HttpClient的使用教程,包括如何创建HTTP请求,执行GET和POST操作,以及设置请求头和处理响应等内容。 - `HTTP中Get与Post的区别.doc`: 深入解析HTTP协议中的GET...
这本"Java并发编程学习笔记"可能是作者在深入研究Java并发特性、工具和最佳实践过程中积累的心得体会。下面,我们将根据这个主题,探讨一些关键的Java并发编程知识点。 1. **线程与进程**:在多任务环境中,线程是...
### Hibernate 3.2 学习笔记:一对一主键关联详解 #### 一、一对一主键关联概述 在本节中,我们将详细探讨 Hibernate 3.2 中的一对一关联关系,尤其是通过主键实现的双向关联。这种关联通常出现在需要紧密绑定两个...
Java JDK6学习笔记是针对Java开发初学者及进阶者的重要参考资料,主要涵盖了JDK6版本中的关键特性和编程实践。这份资料源自台湾JavaWorld论坛,由经验丰富的开发者分享,旨在帮助读者深入理解和掌握Java编程语言的...
Java线程学习笔记涉及了Java多线程编程的多个关键知识点,本篇知识点整理将详细解释每个概念及其在Java中的实现方式。 基本知识部分包含了Java线程编程的基础内容,它们是并发编程的基石。 任务Runnable是一个接口...
《良葛格Java JDK 5.0学习笔记》是一份专为Java初学者及爱好者精心编写的教程,它深入浅出地介绍了Java编程语言的核心概念和技术。这份教材以JDK 5.0版本为基础,该版本是Java发展史上的一个重要里程碑,引入了许多...
但过度使用可能导致内存泄漏,因为线程结束时,ThreadLocal的值不会自动清除,除非手动调用remove()。 4. **ReentrantReadWriteLock**: 读写锁允许多个读线程同时访问资源,但在写操作时会独占资源。这种锁提高了...
本学习笔记将深入探讨JUC的基础知识,帮助你理解和掌握Java并发编程的核心概念。 在Java中,多线程是实现并发的主要方式。一个线程是程序执行的一个流,多线程则意味着一个程序内可以同时执行多个线程。Java提供了...
以下是对"良葛格Java JDK 5.0学习笔记fuluB"中可能涵盖的关键知识点的详细解释: 1. **泛型**:JDK 5.0引入了泛型,允许在编译时检查类型安全,减少了强制类型转换的需要。泛型可以用于类、接口和方法,有助于编写...
本笔记将深入探讨无锁编程的概念、原理以及在Java中的实现方式。 首先,理解无锁编程的核心思想是关键。无锁编程,也称为Lock-Free Programming,是指在多线程环境下,通过避免使用传统的锁机制(如synchronized或...
### JavaSE基础学习笔记 #### 一、Java概述与历史 - **起源与发展**:Java最初由Sun Microsystems在1995年推出,后被Oracle公司收购并继续发展。Java经历了多个版本的发展,逐渐形成了Java SE(Standard Edition,...
本学习笔记将深入探讨Java多线程的相关知识,包括其原理、实现方式、同步机制以及常见问题。 ### 一、多线程的基本概念 多线程是指在一个程序中存在两个或更多的执行线程,这些线程共享同一内存空间,但各自拥有...
### Acegi学习笔记详解 #### 一、Acegi Security概览 **Acegi Security**,作为Spring Security的前身,是一个深度融入Spring Framework的安全框架,它为开发者提供了一套全面的安全解决方案,尤其在Web应用程序中...
本篇笔记将深入探讨Java中的并发同步机制,包括核心概念、工具类以及在实际开发中的应用。 首先,我们要理解什么是线程安全。线程安全是指在多线程环境下,一个方法或类能够正确处理多个线程同时访问的情况,不会...
本篇笔记主要关注并发编程中的两个关键概念:CAS(Compare and Swap)原子操作和Java线程的深入理解。 首先,我们来详细探讨一下CAS(比较并交换)原子操作。CAS是一种无锁算法,它通过比较内存中的某个值与期望值...
在本文中,我们将深入探讨Java多线程的相关知识点,并结合提供的源代码进行学习。 1. **线程的创建** - **实现Runnable接口**:创建一个类实现Runnable接口,然后将其实例传递给Thread类的构造函数,如`Thread t =...
### Java分布式应用学习笔记03:JVM对线程的资源同步和交互机制 在深入探讨Java虚拟机(JVM)如何处理线程间的资源同步与交互机制之前,我们先来明确几个关键概念:线程、多线程、同步、并发以及它们在Java中的实现...