Java 线程局部存储

本文介绍了Java中的ThreadLocal类,用于实现线程局部变量。每个线程都有自己的副本,不互相干扰。ThreadLocal通常作为静态字段存在于类中,用于保存与线程相关的数据。通过get和set方法,不同线程可以独立地读写数据。实现原理主要是通过内部类ThreadLocalMap存储在Thread对象中,确保线程间数据隔离。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一,简介和应用

Java中对线程局部存储进行支持的类是:

public class ThreadLocal<T> extends Object

其文档解释为:

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

解释下这段话:

  1,该类提供“线程局部存储技术”。即尽管表面上,访问的都是这个类的get()方法和set()方法,但是不同的线程设置的和获取的数据是不同的。

  2,该类往往是作为其他类的private static字段存在,用以保持一个与线程本身有关的变量的。


方法摘要
 Tget()
          返回此线程局部变量的当前线程副本中的值。
protected  TinitialValue()
          返回此线程局部变量的当前线程的“初始值”。
 voidremove()
          移除此线程局部变量当前线程的值。
 voidset(T value)
          将此线程局部变量的当前线程副本中的值设置为指定值。

例如,任务类Task被作为线程池的任务执行,线程池的线程执行任务需要统计执行的线程数,因此,这个数可以作为线程局部存储的数据。


public class Task implements Runnable{


    private static final ThreadLocal threadLocal = new ThreadLocal();

    public void run() {

        Integer in = (Integer)threadLocal.get();

        if(in == null){
            //线程里没有该数据,说明是第一次执行
            threadLocal.set(new Integer(1));

        }else{
            //线程中有该数据,则应该进行更新
            threadLocal.set(in+1);

        }

        //执行任务的时候打印下目前已经有多少任务是由该线程执行的

        System.out.println(threadLocal.get().toString()+"  tasks are run by this thread. ");

   }

}


二,实现原理

  这种机制的实现其实很简单。类ThreadLocal中有个内部类ThreadLocalMap 其是 ThreadLocal 和 所设定的值的Key-Value键值对。 例如对于上述例子,第一次则对应的为 threadLocal -- Integer(1)。但是该ThreadLocalMap的实例,则存储于线程中,是线程类的成员变量。

 因此

  1.   public T get() {  
  2.         Thread t = Thread.currentThread();  
  3.         ThreadLocalMap map = getMap(t);  
  4.         if (map != null)  
  5.             return (T)map.get(this);  
  6.   
  7.         // Maps are constructed lazily.  if the map for this thread  
  8.         // doesn't exist, create it, with this ThreadLocal and its  
  9.         // initial value as its only entry.  
  10.         T value = initialValue();  
  11.         createMap(t, value);  
  12.         return value;  
  13.     }
  14.   
  15.  ThreadLocalMap getMap(Thread t) {
  16.         return t.threadLocals;
  17.    }   

如上源代码所示,get()方法先调用getMap(Thread t)方法获取线程的成员变量threadLocals,然后从这个threadLocals中以本ThreadLocal 实例为参数获取其值。

对应的set()方法:

  1.     public void set(T value) {  
  2.         Thread t = Thread.currentThread();  
  3.         ThreadLocalMap map = getMap(t);  
  4.         if (map != null)  
  5.             map.set(this, value);  
  6.         else  
  7.             createMap(t, value);  
  8.     } 
也是从线程中获取其成员变量然后去设置它的(如果没有则创建它,并设置第一个ThreadLocal-值 的映射)。


因此,实际上这个类都是从线程的成员变量中获取自己这个类的实例对应的值的。因此尽管类的参数相同,都是自己,但是不同线程导致数据来源不同,因此设置和获取都是线程自己的成员变量。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值