- 浏览: 285595 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
zhengalways:
samwalt 写道zhengalways 写道samwalt ...
“程序包com.sun.image.codec.jpeg不存在”问题解决 -
samwalt:
zhengalways 写道samwalt 写道zhengal ...
“程序包com.sun.image.codec.jpeg不存在”问题解决 -
zhengalways:
samwalt 写道zhengalways 写道博主你好,刚用 ...
“程序包com.sun.image.codec.jpeg不存在”问题解决 -
samwalt:
zhengalways 写道博主你好,刚用idea,切换成jr ...
“程序包com.sun.image.codec.jpeg不存在”问题解决 -
zhengalways:
博主你好,刚用idea,切换成jre也不行啊,崩溃
“程序包com.sun.image.codec.jpeg不存在”问题解决
一、概述
ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。
从线程的角度看,每个线程都保持一个对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
通过ThreadLocal存取的数据,总是与当前线程相关,也就是说,JVM 为每个运行的线程,绑定了私有的本地实例存取空间,从而为多线程环境常出现的并发访问问题提供了一种隔离机制。
ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
二、API说明
ThreadLocal()
创建一个线程本地变量。
T get()
返回此线程局部变量的当前线程副本中的值,如果这是线程第一次调用该方法,则创建并初始化此副本。
protected T initialValue()
返回此线程局部变量的当前线程的初始值。最多在每次访问线程来获得每个线程局部变量时调用此方法一次,即线程第一次使用 get() 方法访问变量的时候。如果线程先于 get 方法调用 set(T) 方法,则不会在线程中再调用 initialValue 方法。
若该实现只返回 null;如果程序员希望将线程局部变量初始化为 null 以外的某个值,则必须为 ThreadLocal 创建子类,并重写此方法。通常,将使用匿名内部类。initialValue 的典型实现将调用一个适当的构造方法,并返回新构造的对象。
void remove()
移除此线程局部变量的值。这可能有助于减少线程局部变量的存储需求。如果再次访问此线程局部变量,那么在默认情况下它将拥有其 initialValue。
void set(T value)
将此线程局部变量的当前线程副本中的值设置为指定值。许多应用程序不需要这项功能,它们只依赖于 initialValue() 方法来设置线程局部变量的值。
在程序中一般都重写initialValue方法,以给定一个特定的初始值。
三、典型实例
1、Hiberante的Session 工具类HibernateUtil
这个类是Hibernate官方文档中HibernateUtil类,用于session管理。
在这个类中,由于没有重写ThreadLocal的initialValue()方法,则首次创建线程局部变量session其初始值为null,第一次调用currentSession()的时候,线程局部变量的get()方法也为null。因此,对session做了判断,如果为null,则新开一个Session,并保存到线程局部变量session中,这一步非常的关键,这也是“public static final ThreadLocal session = new ThreadLocal()”所创建对象session能强制转换为Hibernate Session对象的原因。
2、另外一个实例
创建一个Bean,通过不同的线程对象设置Bean属性,保证各个线程Bean对象的独立性。
运行结果:
a is running!
thread a set age to:76
b is running!
thread b set age to:27
thread a first read age is:76
thread b first read age is:27
thread a second read age is:76
thread b second read age is:27
可以看到a、b两个线程age在不同时刻打印的值是完全相同的。这个程序通过妙用ThreadLocal,既实现多线程并发,游兼顾数据的安全性。
四、总结
ThreadLocal使用场合主要解决多线程中数据数据因并发产生不一致问题。ThreadLocal为每个线程的中并发访问的数据提供一个副本,通过访问副本来运行业务,这样的结果是耗费了内存,单大大减少了线程同步所带来性能消耗,也减少了线程并发控制的复杂度。
ThreadLocal不能使用原子类型,只能使用Object类型。ThreadLocal的使用比synchronized要简单得多。
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。
五、ThreadLocal使用的一般步骤
1、在多线程的类(如ThreadDemo类)中,创建一个ThreadLocal对象threadXxx,用来保存线程间需要隔离处理的对象xxx。
2、在ThreadDemo类中,创建一个获取要隔离访问的数据的方法getXxx(),在方法中判断,若ThreadLocal对象为null时候,应该new()一个隔离访问类型的对象,并强制转换为要应用的类型。
3、在ThreadDemo类的run()方法中,通过getXxx()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象。
ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。
从线程的角度看,每个线程都保持一个对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
通过ThreadLocal存取的数据,总是与当前线程相关,也就是说,JVM 为每个运行的线程,绑定了私有的本地实例存取空间,从而为多线程环境常出现的并发访问问题提供了一种隔离机制。
ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
二、API说明
ThreadLocal()
创建一个线程本地变量。
T get()
返回此线程局部变量的当前线程副本中的值,如果这是线程第一次调用该方法,则创建并初始化此副本。
protected T initialValue()
返回此线程局部变量的当前线程的初始值。最多在每次访问线程来获得每个线程局部变量时调用此方法一次,即线程第一次使用 get() 方法访问变量的时候。如果线程先于 get 方法调用 set(T) 方法,则不会在线程中再调用 initialValue 方法。
若该实现只返回 null;如果程序员希望将线程局部变量初始化为 null 以外的某个值,则必须为 ThreadLocal 创建子类,并重写此方法。通常,将使用匿名内部类。initialValue 的典型实现将调用一个适当的构造方法,并返回新构造的对象。
void remove()
移除此线程局部变量的值。这可能有助于减少线程局部变量的存储需求。如果再次访问此线程局部变量,那么在默认情况下它将拥有其 initialValue。
void set(T value)
将此线程局部变量的当前线程副本中的值设置为指定值。许多应用程序不需要这项功能,它们只依赖于 initialValue() 方法来设置线程局部变量的值。
在程序中一般都重写initialValue方法,以给定一个特定的初始值。
三、典型实例
1、Hiberante的Session 工具类HibernateUtil
这个类是Hibernate官方文档中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,第一次调用currentSession()的时候,线程局部变量的get()方法也为null。因此,对session做了判断,如果为null,则新开一个Session,并保存到线程局部变量session中,这一步非常的关键,这也是“public static final ThreadLocal session = new ThreadLocal()”所创建对象session能强制转换为Hibernate Session对象的原因。
2、另外一个实例
创建一个Bean,通过不同的线程对象设置Bean属性,保证各个线程Bean对象的独立性。
public class Student { private int age = 0; //年龄 public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } }
public class ThreadLocalDemo implements Runnable { //创建线程局部变量studentLocal,在后面你会发现用来保存Student对象 private final static ThreadLocal studentLocal = new ThreadLocal(); public static void main(String[] agrs) { ThreadLocalDemo td = new ThreadLocalDemo(); Thread t1 = new Thread(td, "a"); Thread t2 = new Thread(td, "b"); t1.start(); t2.start(); } public void run() { accessStudent(); } /** * 示例业务方法,用来测试 */ public void accessStudent() { //获取当前线程的名字 String currentThreadName = Thread.currentThread().getName(); System.out.println(currentThreadName + " is running!"); //产生一个随机数并打印 Random random = new Random(); int age = random.nextInt(100); System.out.println("thread " + currentThreadName + " set age to:" + age); //获取一个Student对象,并将随机数年龄插入到对象属性中 Student student = getStudent(); student.setAge(age); System.out.println("thread " + currentThreadName + " first read age is:" + student.getAge()); try { Thread.sleep(500); } catch (InterruptedException ex) { ex.printStackTrace(); } System.out.println("thread " + currentThreadName + " second read age is:" + student.getAge()); } protected Student getStudent() { //获取本地线程变量并强制转换为Student类型 Student student = (Student) studentLocal.get(); //线程首次执行此方法的时候,studentLocal.get()肯定为null if (student == null) { //创建一个Student对象,并保存到本地线程变量studentLocal中 student = new Student(); studentLocal.set(student); } return student; } }
运行结果:
a is running!
thread a set age to:76
b is running!
thread b set age to:27
thread a first read age is:76
thread b first read age is:27
thread a second read age is:76
thread b second read age is:27
可以看到a、b两个线程age在不同时刻打印的值是完全相同的。这个程序通过妙用ThreadLocal,既实现多线程并发,游兼顾数据的安全性。
四、总结
ThreadLocal使用场合主要解决多线程中数据数据因并发产生不一致问题。ThreadLocal为每个线程的中并发访问的数据提供一个副本,通过访问副本来运行业务,这样的结果是耗费了内存,单大大减少了线程同步所带来性能消耗,也减少了线程并发控制的复杂度。
ThreadLocal不能使用原子类型,只能使用Object类型。ThreadLocal的使用比synchronized要简单得多。
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。
五、ThreadLocal使用的一般步骤
1、在多线程的类(如ThreadDemo类)中,创建一个ThreadLocal对象threadXxx,用来保存线程间需要隔离处理的对象xxx。
2、在ThreadDemo类中,创建一个获取要隔离访问的数据的方法getXxx(),在方法中判断,若ThreadLocal对象为null时候,应该new()一个隔离访问类型的对象,并强制转换为要应用的类型。
3、在ThreadDemo类的run()方法中,通过getXxx()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象。
发表评论
-
Argument [JSONObject] is of type Model or Map but is not assignable from the act
2016-05-30 15:16 1177/** * 参数前加上@RequestBody即可 * ... -
org.apache.ibatis.reflection.ReflectionException: There is no getter for propert
2016-02-22 18:39 1068在使用mybatis的模糊查询的时候,需要从jsp传入到con ... -
Tomcat以debug模式启动
2015-09-15 14:25 960在catalina.sh文件中加入一行 CATALINA_OP ... -
mybatis自增主键配置
2015-09-07 19:46 1488mybatis进行插入操作时,如果表的主键是自增的,针对不同的 ... -
用mybatis生成代码向oracle插入数据的错误
2015-08-11 11:15 837用mybatis生成的insert方法和mapper文件向or ... -
MyBatis 根据表结构自动生成代码
2015-08-11 11:06 2548需要mybatis-generator-core-1.3.2. ... -
“程序包com.sun.image.codec.jpeg不存在”问题解决
2015-08-07 10:12 6127编译出错:程序包com.sun.image.codec.jpe ... -
spring 3.2.0ga 测试框架(转)
2013-09-26 11:32 941spring3.2终于出ga版了, 发现spring test ... -
Spring MVC自定义拦截器
2013-09-11 11:51 1940自定义拦截器要实现org.springframework.we ... -
Hibernate错误解决
2013-06-20 19:17 827抛异常: org.hibernate.ObjectNotFou ... -
解决@PostConstruct注解的方法不执行的问题
2013-06-06 11:59 23884除了 xmlns:context="http://w ... -
指定java程序运行的所有依赖包
2013-04-28 16:21 1525假如所有依赖包都放在dependency目录中, java ... -
maven
2013-04-28 15:12 35931、用mvn compile编译代码,出现错误:[ERROR] ... -
使用HttpSessionListener接口监听Session的创建和失效
2013-04-24 10:57 1864javax.servlet.http Interface H ... -
XMLbeans使用教程
2013-03-03 17:07 7091Hibernate已经成为目前流行的面向Java环境的对象/关 ... -
获取cookie和保存cookie
2012-11-08 14:32 10461、获取cookie 根据请求获取cookie数组,然后遍历 ... -
用Jackson实现json和java对象相互转换
2012-10-25 12:25 4066java对象不能是内部类 <dependency> ... -
log4j配置详解
2012-10-24 21:35 1236log4j.properties文件放在res ... -
HttpClient 3.1 发送 post请求
2012-09-24 15:13 4878HttpClient 3.1 HttpClient http ... -
Web应用中使用velocity生成文件
2012-08-29 16:05 1414xml文件中配置org.springframework.web ...
相关推荐
Java中的ThreadLocal是一个非常重要的工具类,它在多线程编程中扮演着独特角色,...总之,ThreadLocal是Java多线程编程中的一个强大工具,但使用时需谨慎,理解其工作原理和潜在风险,才能更好地利用它来解决实际问题。
### Java中ThreadLocal详解 #### 一、ThreadLocal概述 在Java多线程编程中,`ThreadLocal`是一个非常重要的工具类,它提供了一种在每个线程内部存储线程私有实例的方法。通常情况下,当多个线程共享某个变量时,...
Java中的`ThreadLocal`类是一个非常实用的工具,它提供了线程局部变量的功能。线程局部变量意味着每个线程都拥有自己独立的变量副本,互不干扰,这在多线程编程中尤其有用,可以避免数据共享带来的同步问题。下面...
当Java事务与ThreadLocal结合使用时,可以在不同的线程中维护各自的事务状态,比如在Spring框架中,每个线程的ThreadLocal可以存储一个TransactionStatus对象,这样就可以在线程内部管理当前事务的状态,而不会影响...
Java中的ThreadLocal是一个非常重要的工具类,它在多线程编程中扮演着独特角色,尤其在处理线程间数据隔离和共享时。ThreadLocal不是线程本身,而是为每个线程提供一个独立的变量副本,使得每个线程都可以独立地改变...
java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多...
java 中ThreadLocal 的正确用法 ThreadLocal 是 Java 中的一个特殊类,它可以让每个线程拥有自己独立的变量副本,避免了多线程之间的共享变量问题。下面我们将详细介绍 Java 中 ThreadLocal 的正确用法。 用法一...
ThreadLocal是Java中的一种机制,可以将变量与线程关联起来,使得每个线程都可以拥有自己的变量副本。 ThreadLocal的出现是为了解决多线程编程中的线程安全问题。 从本质上说,ThreadLocal是一种存储机制,它可以在...
以下是一个完整的ThreadLocal示例,演示了如何在一个Runnable实例中使用ThreadLocal: ```java public class ThreadLocalExample { public static class MyRunnable implements Runnable { private ThreadLocal...
线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突...
在ThreadLocal中,`set()`方法用于设置当前线程的ThreadLocal变量值,`get()`方法用于获取当前线程的ThreadLocal变量值。 ```java threadLocal.set("Hello, ThreadLocal"); String value = threadLocal.get(); ``` ...
Java 中的 ThreadLocal 实例分析是指在多线程环境下,如何使用 ThreadLocal 来实现线程安全。ThreadLocal 是 Java 中的一种机制,用于在多个线程中实现变量的隔离。 在上面的代码中,我们可以看到,ConsumeClientA ...
在本文中,我们将详细介绍Java ThreadLocal的使用案例,并通过一个实际的优化案例,帮助大家理解ThreadLocal的使用。 ThreadLocal的使用场景 在Java多线程编程中,变量的线程安全是一个非常重要的问题。特别是在...
Java线程编程中的ThreadLocal类是一个非常重要的工具,它在多线程环境下提供了一种线程局部变量的机制。ThreadLocal并非是简单的变量,而是一种能够确保每个线程都拥有独立副本的变量容器。理解ThreadLocal的工作...
ThreadLocal是Java中用于线程局部变量的一个工具类,它的工作原理主要体现在如何在不同的线程之间隔离变量的副本,确保每个线程拥有自己的独立数据。这个设计模式在多线程编程中尤其有用,因为它避免了传统的同步...
在这个例子中,getSession()方法会检查ThreadLocal中是否存在Session,若不存在则创建并设置,而closeSession()方法则负责关闭并移除当前线程的Session副本。 总结来说,ThreadLocal是Java中解决多线程数据隔离问题...
文章详细讲解了ThreadLocal中关键方法get、set、remove的操作流程,并解释了其中使用弱引用作为键的Entry的原因是为了避免内存泄漏的问题。此外,文中还探讨了线程池中使用ThreadLocal可能出现的记忆泄漏风险及其...
ThreadLocalMap并不直接继承自java.util.Map,而是使用WeakReference来保存ThreadLocal实例作为键。这样做的好处是,当一个ThreadLocal变量不再被引用时,可以被垃圾收集器回收,避免内存泄漏。而Value部分则存储了...
彻底理解Java中的ThreadLocal ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量。使用这个工具类可以很简洁地编写出优美的多线程程序。ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这...
NULL 博文链接:https://bijian1013.iteye.com/blog/2380233