`

ThreadLocal 源码分析

阅读更多

    之前曾转载过相关ThreadLocal的文章,但一直是处于迷糊状态,最近复习的时候偶然看到博客里的文章,所以对此类做一个深入的分析和总结。

(另外说明下,我这个源码的Java 版本是1.6.0_06)

 

    在Java API 文档里,是这样解释的:

该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。

    这里有两个关键字,“线程局部变量”和“初始化副本”。这两个关键字基本涵盖了这个类的含义。

   “线程局部变量”是指在同一个线程中,该变量是唯一的(可以把这个变量理解为同个线程内的单例)。

   “初始化副本”是指在不同线程中,该变量是你定义的那个初始值(也就是那个副本)。

 

   下面是Java API 的例子:

    以下类生成对每个线程唯一的局部标识符(就是说在同一个线程内是不会出现两个相同的uniqueId的)。线程 ID 是在第一次调用 UniqueThreadIdGenerator.getCurrentThreadId() 时分配的,在后续调用中不会更改。

 

import java.util.concurrent.atomic.AtomicInteger;

 public class UniqueThreadIdGenerator {

     private static final AtomicInteger uniqueId = new AtomicInteger(0);

     private static final ThreadLocal < Integer > uniqueNum = 
         new ThreadLocal < Integer > () {
//定义初始值(副本)
             @Override protected Integer initialValue() {
                 return uniqueId.getAndIncrement();
         }
     };
 
     public static int getCurrentThreadId() {
//API 上的例子是下面的,不过我以为应该是写错了,因为这样的话每次获得的uniqueId是不变的,都是0
     //    return uniqueId.get();
//我修改后的代码如下,就是把uniqueId换成uniqueNum 
           return uniqueNum.get();
     }
 } // UniqueThreadIdGenerator

 

   下面是对ThreadLocal 类的源码分析下:

   void set(Object value):设置当前线程的线程局部变量的值。
   public Object get() :该方法返回当前线程所对应的线程局部变量。 (同一个线程获取同一个变量的引用)
   public void remove() :将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。

   protected Object initialValue():返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的(在上面的例子也可以看到,其实就是一个默认值的设置)。这个方法是一个延迟调用方法,在线程第1次调用 get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。

 

   1、void set(Object value)方法分析

public void set(T value) {
        Thread t = Thread.currentThread();
//查看当前线程中的ThreadLocalMap 是否存在。
        ThreadLocalMap map = getMap(t);
//存在的话就把当前线程设置进ThreadLocalMap中。
        if (map != null)
            map.set(this, value);
        else
//否则生成一个ThreadLocalMap 对象,并把值赋到当前线程的ThreadLocalMap中
            createMap(t, value);
    }
//-------------------------------解析的代码分割线-------------------------------

//返回当前线程的ThreadLocalMap 
ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
//创建新的ThreadLocalMap赋值到当前线程
 void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

 

 

 

 

    下面说下关于ThreadLocalMap 类,这个类有点类似于WeakHashMap(这个类对于解决某些问题提供了很好的性能上的方案,有空再继续深入了解。),虽然ThreadLocalMap没有继承Map的,但它具有Map的一些特性,有关这些特性就不说了,主要说说它们的一个很大的共同点就是,它们的key 都是弱引用的对象,因此在该键没有被引用时,将会被JVM收集。(有关弱引用的解析,请参考我的博客上的:http://zhxing.iteye.com/admin/blogs/571007

ThreadLocalMap是ThreadLocal的一个嵌套类,它的一些源码如下:

    static class ThreadLocalMap {

        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
        static class Entry extends WeakReference<ThreadLocal> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal k, Object v) {
                super(k);
                value = v;
            }
        }

 

2、 public Object get()  方法分析

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
        //这个是传入当前的ThreadLocal 对象引用获取所对应的值
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
  //如果map 对象为空,说明是第一次调用这个方法,之前也没有调用set()方法
        return setInitialValue();
    }
//-------------------------------解析的代码分割线-------------------------------
//这个方法很简单就是调用initialValue()获取初始值(默认值),而且要赋值在当前线程的map中(相当于调用了set()方法)
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }
//ThreadLocal 的默认实现是返回null 的,所以如果在多个线程中使用时,如果需要用到默认值,那子类就应该覆盖该值
    protected T initialValue() {
        return null;
    }

 

 

 

3、public void remove() 方法

//这个方法没什么可说的,就是删除掉当前线程中的变量(释放内存)
public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

 

总结

 

 

   ThreadLocal 可以实现在同一个线程内共享一个变量,不同的线程不能共享,只能得到该变量的一个副本(就是一个默认的初始化值)。

     在论坛中也有人提到ThreadLocal和synchronized 的问题,我觉得它们都是解决线程的两个不同的方案。ThreadLocal解决的是同一个线程内的资源共享问题,而synchronized 解决的是多个线程间的资源共享问题。

有关的讨论在:http://www.iteye.com/topic/179040

 

有关这个类的应用,可以参考http://zhxing.iteye.com/admin/blogs/306070

 

 

1
3
分享到:
评论

相关推荐

    ThreadLocal源码分析

    首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象。

    ThreadLocal源码分析和使用

    ThreadLocal 源码分析和使用 ThreadLocal 是 Java 语言中的一种多线程编程机制,用于解决多线程程序的并发问题。它不是一个 Thread,而是一个 Thread 的局部变量。ThreadLocal 的出现是为了解决多线程程序中的共享...

    ThreadLocal_ThreadLocal源码分析_

    **ThreadLocal概述** ThreadLocal是Java中的一个线程局部变量类,它为每个线程创建了一个独立的变量副本。这意味着每个线程都有自己的ThreadLocal变量,互不干扰,提供了线程安全的数据存储方式。ThreadLocal通常...

    ThreadLocal_ThreadLocal源码分析_源码.zip

    同时,`ThreadLocalMap`的构造、扩容、收缩以及弱引用的处理等都是源码分析的重点。 总的来说,ThreadLocal是一个强大的工具,可以有效解决多线程环境中的数据隔离问题,但在使用过程中需要注意内存管理,防止潜在...

    Java并发编程学习之ThreadLocal源码详析

    Java并发编程学习之ThreadLocal源码详析 ThreadLocal是Java并发编程中的一种机制,用于解决多线程访问共享变量的问题。它可以使每个线程对共享变量的访问都是线程安全的,使得多线程编程变得更加简单。 ...

    java并发包源码分析(3)ThreadLocal

    Java并发编程中,ThreadLocal是一个非常重要的类,它是解决线程安全问题的一个工具。ThreadLocal提供了一种在多线程环境下使用“共享变量”的方式,但是它实际上是为每个线程提供一个变量的副本,这样每个线程都可以...

    ThreadLocal 线程本地变量 及 源码分析.rar_开发_设计

    以上是对ThreadLocal的简单介绍和源码分析,实际使用中还需要结合具体业务场景进行合理设计和优化。通过深入理解ThreadLocal的工作原理,可以帮助我们更好地利用这一工具,提高代码的并发性能和可维护性。

    Java源码解析ThreadLocal及使用场景

    ThreadLocal的源码分析: 首先是类的介绍。ThreadLocal类提供了线程本地变量。这些变量使每个线程都有自己的一份拷贝。ThreadLocal期望能够管理一个线程的状态,例如用户id或事务id。 ThreadLocal的使用有很多...

    ThreadLocal的原理,源码深度分析及使用.docx

    ThreadLocal 的原理、源码深度分析及使用 ThreadLocal 是 Java 语言中的一种机制,用于实现线程本地存储,能够帮助开发者在多线程环境下解决变量访问安全的问题。下面将对 ThreadLocal 的原理、实现机制、使用方法...

    druid 源码分析 逐层详解

    标题所指的知识点为“Druid 源码分析 逐层详解”,意味着我们需要深入分析Druid这一开源数据处理工具的源码,并从不同的层面揭示其内部实现机制。 首先,我们来看Druid的构架设计。Druid采用了分层的架构,每个层次...

    ThreadLocal分析

    在分析ThreadLocal源码时,可以了解到它如何在内部实现线程隔离,以及ThreadLocalMap的结构和工作方式。理解这些细节有助于我们更好地利用ThreadLocal,同时避免可能出现的问题。通过阅读源码,我们可以发现...

    ThreadLocal内存泄露分析

    【标题】:“ThreadLocal内存泄露分析” 在Java编程中,ThreadLocal是一个强大的工具类,它为每个线程提供了一个独立的变量副本,使得每个线程都可以独立地改变自己的副本,而不会影响其他线程所对应的副本。然而,...

    JUC并发编程与源码分析视频课.zip

    《JUC并发编程与源码分析视频课》是一门深入探讨Java并发编程的课程,主要聚焦于Java Util Concurrency(JUC)库的使用和源码解析。JUC是Java平台提供的一组高级并发工具包,它极大地简化了多线程编程,并提供了更...

    threadLocal

    源码分析: 在Java的`ThreadLocal`实现中,每个线程都有一个`ThreadLocalMap`,它是`ThreadLocal`的一个内部类,用于存储线程局部变量。`ThreadLocalMap`使用弱引用作为键,目的是在线程不再引用ThreadLocal对象时,...

    ThreadLocal的用处

    6. **源码分析**: ThreadLocal类的核心在于`initialValue()`方法和`get()`方法。`initialValue()`是线程首次访问ThreadLocal变量时调用的,返回的是默认值。`get()`方法则会查找当前线程的ThreadLocalMap,如果...

    JDK的ThreadLocal理解(一)使用和测试

    **标题:“JDK的ThreadLocal理解(一)使用...通过以上分析,我们可以看到ThreadLocal在实现线程间数据隔离、简化多线程编程方面的作用。然而,使用时也要注意避免内存泄漏和过度依赖,合理规划其在系统架构中的位置。

    ThreadLocal

    5. **源码分析**: - `ThreadLocal`类在`java.lang`包下,它的实现主要依赖于`Thread`类的成员变量`threadLocals`,这是一个`ThreadLocalMap`实例,`ThreadLocalMap`是`WeakReference&lt;ThreadLocal&lt;?&gt;&gt;`和`Object`...

    对ThreadLocal的理解【源码分析+应用举例】

    一、简介 ThreadLocal是JDK包提供的,它提供了线程本地变量,也就是如果你创建了一个ThreadLocal变量,那么访问这个变量的每一个线程都会有这个变量的一个本地副本。...根据源码,画出ThreadLocal原理图 原创文章

    java并发源码分析之实战编程

    "java并发源码分析之实战编程"这个主题深入探讨了Java平台上的并发处理机制,旨在帮助开发者理解并有效地利用这些机制来提高程序性能和可扩展性。在这个专题中,我们将围绕Java并发库、线程管理、锁机制、并发容器...

    hibernate源码分析一[启动过程]

    标题:hibernate源码分析一[启动过程] 在深入探讨Hibernate框架的启动过程之前,我们首先需要了解几个核心的概念和类,它们是Hibernate启动流程的基石。 ### 1. 关键类与接口 #### Environment类 `Environment`类...

Global site tag (gtag.js) - Google Analytics