`
王牌海盗
  • 浏览: 239155 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

ThreadLocal知识总结

阅读更多

昨天的在看hibernate文档的时候看到了个“新词”:Threadlocal,以前没见过。在网上查了下资料学习了一下,特整理如下:

ThreadLocal是什么?

ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是thread local variable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。其实线程局部变量(ThreadLocal)的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量。线程局部变量并不是Java的新发明,在其它的一些语言编译器实现(如IBM XL FORTRAN)中,它在语言的层次提供了直接的支持。因为Java中没有提供在语言层次的直接支持,而是提供了一个ThreadLocal的类来提供支持,所以,在Java中编写线程局部变量的代码相对比较笨拙,这也许是线程局部变量没有在Java中得到很好的普及的一个原因吧。

ThreadLocal的设计?

首先看看ThreadLocal的接口:

Object get() ;

// 返回当前线程的线程局部变量副本 protected Object initialValue(); // 返回该线程局部变量的当前线程的初始值

void set(Object value);

// 设置当前线程的线程局部变量副本的值

ThreadLocal有3个方法,其中值得注意的是initialValue(),该方法是一个protected的方法,显然是为了子类重写而特意实现的。该方法返回当前线程在该线程局部变量的初始值,这个方法是一个延迟调用方法,在一个线程第1次调用get()或者set(Object)时才执行,并且仅执行1次。ThreadLocal中的实现是直接返回一个null:

protected Object initialValue() { return null; }

ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。

比如下面的示例实现:

java 代码
  1. public class ThreadLocal   
  2.   
  3. {   
  4.   
  5. private Map values = Collections.synchronizedMap(new HashMap());   
  6.   
  7. public Object get()   
  8.   
  9. {   
  10.   
  11. Thread curThread = Thread.currentThread();   
  12.   
  13. Object o = values.get(curThread);   
  14.   
  15. if (o == null && !values.containsKey(curThread)){   
  16.   
  17.        o = initialValue();   
  18.   
  19.        values.put(curThread, o);   
  20.   
  21.     }   
  22.   
  23.     return o;   
  24.   
  25. }   
  26.   
  27.   
  28. public void set(Object newValue)   
  29.   
  30. {   
  31.   
  32. values.put(Thread.currentThread(), newValue);   
  33.   
  34. }   
  35.   
  36.   
  37. public Object initialValue()   
  38.   
  39. {   
  40.   
  41. return null;   
  42.   
  43. }   
  44.   
  45. }  

当然,这并不是一个工业强度的实现,但JDK中的ThreadLocal的实现总体思路也类似于此。

ThreadLocal的使用

如果希望线程局部变量初始化其它值,那么需要自己实现ThreadLocal的子类并重写该方法,通常使用一个内部匿名类对ThreadLocal进行子类化,比如下面的例子,SerialNum类为每一个类分配一个序号

java 代码
  1. public class SerialNum   
  2.   
  3. {   
  4.   
  5. // The next serial number to be assigned   
  6.   
  7.   
  8. private static int nextSerialNum = 0;   
  9.   
  10. private static ThreadLocal serialNum = new ThreadLocal()   
  11.   
  12. {   
  13.   
  14. protected synchronized Object initialValue()   
  15.   
  16. {   
  17.   
  18. return new Integer(nextSerialNum++);   
  19.   
  20. }   
  21.   
  22. };   
  23.   
  24.   
  25. public static int get()   
  26.   
  27. {   
  28.   
  29. return ((Integer) (serialNum.get())).intValue();   
  30.   
  31. }   
  32.   
  33. }  

SerialNum类的使用将非常地简单,因为get()方法是static的,所以在需要获取当前线程的序号时,简单地调用:

int serial = SerialNum.get(); 即可。

在线程是活动的并且ThreadLocal对象是可访问的时,该线程就持有一个到该线程局部变量副本的隐含引用,当该线程运行结束后,该线程拥有的所以线程局部变量的副本都将失效,并等待垃圾收集器收集。


ThreadLocal与其它同步机制的比较

ThreadLocal和其它同步机制相比有什么优势呢?ThreadLocal和其它所有的同步机制都是为了解决多线程中的对同一变量的访问冲突,在普通的同步机制中,是通过对象加锁来实现多个线程对同一变量的安全访问的。这时该变量是多个线程共享的,使用这种同步机制需要很细致地分析在什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放该对象的锁等等很多。所有这些都是因为多个线程共享了资源造成的。ThreadLocal就从另一个角度来解决多线程的并发访问,ThreadLocal会为每一个线程维护一个和该线程绑定的变量的副本,从而隔离了多个线程的数据,每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的整个变量封装进ThreadLocal,或者把该对象的特定于线程的状态封装进ThreadLocal。

由于ThreadLocal中可以持有任何类型的对象,所以使用ThreadLocal get当前线程的值是需要进行强制类型转换。但随着新的Java版本(1.5)将模版的引入,新的支持模版参数的ThreadLocal类将从中受益。也可以减少强制类型转换,并将一些错误检查提前到了编译期,将一定程度地简化ThreadLocal的使用。

总结

当然ThreadLocal并不能替代同步机制,两者面向的问题领域不同。同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信的有效方式;而ThreadLocal是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源(变量),这样当然不需要对多个线程进行同步了。所以,如果你需要进行多个线程之间进行通信,则使用同步机制;如果需要隔离多个线程之间的共享冲突,可以使用ThreadLocal,这将极大地简化你的程序,使程序更加易读、简洁。


ThreadLocal的几种误区

一、ThreadLocal是java线程的一个实现
        ThreadLocal的确是和java线程有关,不过它并不是java线程的一个实现,它只是用来维护本地变量。针对每个线程,提供自己的变量版本,主要是为了避免线程冲突,每个线程维护自己的版本。彼此独立,修改不会影响到对方。
二、ThreadLocal是相对于每个session的
          ThreadLocal顾名思义,是针对线程。在java web编程上,每个用户从开始到会话结束,都有自己的一个session标识。但是ThreadLocal并不是在会话层上。其实,Threadlocal是独立于用户session的。它是一种服务器端行为,当服务器每生成一个新的线程时,就会维护自己的ThreadLocal。对于这个误解,个人认为应该是开发人员在本地基于一些应用服务器测试的结果。众所周知,一般的应用服务器都会维护一套线程池,也就是说,对于每次访问,并不一定就新生成一个线程。而是自己有一个线程缓存池。对于访问,先从缓存池里面找到已有的线程,如果已经用光,才去新生成新的线程。所以,由于开发人员自己在测试时,一般只有他自己在测,这样服务器的负担很小,这样导致每次访问可能是共用同样一个线程,导致会有这样的误解:每个session有一个ThreadLocal
三、ThreadLocal是相对于每个线程的,用户每次访问会有新的ThreadLocal
    理论上来说,ThreadLocal是的确是相对于每个线程,每个线程会有自己的ThreadLocal。但是上面已经讲到,一般的应用服务器都会维护一套线程池。因此,不同用户访问,可能会接受到同样的线程。因此,在做基于TheadLocal时,需要谨慎,避免出现ThreadLocal变量的缓存,导致其他线程访问到本线程变量(这个我们的ef项目就遇到过,需特别注意)
四、对每个用户访问,ThreadLocal可以多用
          可以说,ThreadLocal是一把双刃剑,用得来的话可以起到非常好的效果。但是,ThreadLocal如果用得不好,就会跟全局变量一样。代码不能重用,不能独立测试。因为,一些本来可以重用的类,现在依赖于ThreadLocal变量。如果在其他没有ThreadLocal场合,这些类就变得不可用了。个人觉得ThreadLocal用得很好的几个应用场合,值得参考
    1、存放当前session用户:quake want的jert
    2、存放一些context变量,比如webwork的ActionContext
    3、存放session,比如Spring hibernate orm的session

分享到:
评论

相关推荐

    Hibernager_Session_Manager_ThreadLocal

    总结起来,"Hibernage_Session_Manager_ThreadLocal"是一个关于使用ThreadLocal在多线程环境中优化Hibernate Session管理的技术实践,通过这种方式可以提升应用程序的性能和安全性。`HibernateUtil.java`是实现这一...

    ThreadLocal,你真的了解吗?

    总结,ThreadLocal 提供了一种线程隔离的变量存储方式,而 Java 中的四种引用类型则帮助我们更好地控制对象的生命周期和内存管理,理解这些概念对于理解和使用 ThreadLocal 至关重要,同时也是面试中经常考察的知识...

    有关ThreadLocal的面试题你真的懂了吗

    "ThreadLocal相关知识点总结" ThreadLocal是Java中的一种机制,用于在多线程环境中保存线程上下文信息,并且提供了一种解决多线程程序并发问题的思路。下面是对ThreadLocal的主要知识点的总结: 1. ThreadLocal的...

    入研究java.lang.ThreadLocal类.docx

    ### 知识点详解:Java.lang.ThreadLocal 类 #### 一、概述 **ThreadLocal** 并非线程的一种特殊实现形式,而是一种为每个线程提供独立副本的机制,通常被称为“线程局部变量”。这种机制使得每个线程都可以独立...

    深入学习java ThreadLocal的源码知识

    总结起来,ThreadLocal提供了一种在多线程环境中安全存储线程局部变量的机制,通过弱引用避免内存泄漏,以及使用开放地址法处理哈希冲突。理解ThreadLocal的原理和源码对于开发高并发的Java应用至关重要,因为它可以...

    Android 中 ThreadLocal使用示例

    总结一下,ThreadLocal的主要知识点包括: 1. **线程隔离**:每个线程拥有ThreadLocal变量的独立副本,互不影响。 2. **共享对象,独立值**:所有线程共享同一个ThreadLocal对象,但访问时看到的是各自的副本。 3. ...

    MS知识点总结.txt

    根据提供的文件信息,我们可以整理出一系列关于Java的重要知识点,这些知识点涵盖了Java基础...以上知识点总结涵盖了Java语言的核心概念和技术细节,对于准备Java面试或希望深入理解Java技术的开发者来说非常有价值。

    Android(Java)

    总结 线程安全是 Android(Java)开发中一个非常重要的话题。线程安全可以通过使用 volatile 和 final 关键字,使用锁机制,使用 ThreadLocal 等方法来实现。ThreadLocal 是 Java 中的一个类,可以确保每个线程都...

    Thinking in Java知识点总结

    10. **线程本地存储**:线程本地变量(`ThreadLocal`)允许每个线程拥有自己的变量副本,避免了线程间的数据冲突。 11. **终止任务**:不推荐使用`suspend()`和`resume()`,它们可能导致死锁。`stop()`也不安全,因为...

    JUC面试知识点总结1

    4. **线程局部变量**:ThreadLocal 类提供线程局部变量,每个线程都有自己的副本,互不影响,从而避免了线程安全问题。 5. **Lock 接口与 ReentrantLock 类**:Lock 接口提供了比 synchronized 更细粒度的锁控制,...

    java面试常见问题总结

    ### Java面试常见问题总结 #### 死锁相关 在Java面试中,死锁是一个非常重要的概念,面试官可能会从不同的角度来考察候选人对于死锁的理解程度。以下是对死锁相关知识点的详细介绍: - **产生死锁的原因:** 1....

    各大公司Java后端开发面试题总结.doc

    Java 后端开发面试题中涉及了许多核心概念,如线程局部变量(ThreadLocal)、同步机制(Synchronized)、垃圾回收(GC)、内存模型、字符串处理(String与StringBuilder)以及并发安全问题。以下是对这些知识点的详细说明: ...

    多线程基础部分.md,学习代码

    在IT行业中,多线程是实现高...总结来说,多线程基础部分的学习涵盖了线程创建、线程状态、线程同步、ThreadLocal的使用以及并发编程的高级概念。通过深入理解这些内容,开发者可以编写出更加高效、稳定的多线程程序。

    各大公司Java后端开发面试题总结

    本篇总结的面试题涵盖了Java基础知识、线程同步、内存模型、垃圾回收机制、锁机制、集合框架以及Java集合中常用的类等知识点。 首先,ThreadLocal是Java多线程编程中的一个重要的概念,它是为了实现线程本地存储而...

    ikm_java_8.pdf

    ### 总结 通过以上分析,我们了解了Java 8中关于多线程安全的一些技巧、JavaScript表单验证的基本原理、如何在Servlet中读取初始化参数以及Swing组件类型的区别。这些知识点对于开发高质量的Java应用程序至关重要。

    Java知识点总结,面试必备,java基础、java集合、JVM、Java并发

    4. **Java并发**:Java提供了丰富的并发编程工具,如线程池、synchronized、volatile、ThreadLocal、Lock等。理解并发编程原理,掌握如何在多线程环境中保证数据一致性,防止死锁、活锁和饥饿现象,是编写高效、稳定...

    春招总结,干货满满1

    这篇文章主要总结了春季招聘面试中的一些核心技术点,特别是关于Java多线程同步的方法。文章提到了七种线程同步的方式,并详细解释了每一种方法的原理和使用场景。以下是对这些知识点的详细说明: 1. **同步方法**...

    Java多线程-知识点梳理和总结-超详细-面试知识点.docx

    "Java多线程-知识点梳理和总结-超详细-面试知识点" Java多线程是Java编程语言中最基本也是最重要的概念之一。多线程编程可以提高程序的执行效率、改善用户体验和提高系统的可扩展性。但是,多线程编程也存在一些...

    2019年总结JAVA架构师核心知识点整理.zip

    2019年总结的Java架构师核心知识点是针对这一专业角色的关键技能和知识的全面整理,旨在帮助专业人士提升其在面试和实际工作中的表现。以下是这份资料中可能涵盖的一些关键知识点: 1. **Java基础**:包括Java语言...

Global site tag (gtag.js) - Google Analytics