经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
Java 中 ThreadLocal的基本原理
来源:cnblogs  作者:不要乱摸  时间:2018/10/12 9:49:31  对本文有异议

1.  ThreadLocal是什么

ThreadLocal提供线程局部变量。这些变量与普通的变量不同之处在于,每个访问这种变量的线程(通过它的get或set方法)都有自己的、独立初始化的变量副本。

ThreadLocal实例通常是希望将状态关联到一个线程的类的私有静态字段(比如,user ID 或者 Transaction ID 等等)。

画外音:这段话表达了三个意思

  1. ThreadLocal是一种变量类型,我们称之为“线程局部变量”

  2. 每个线程访问这种变量的时候都会创建该变量的副本,这个变量副本为线程私有

  3. ThreadLocal类型的变量一般用private static加以修饰

例如,下面的例子中这个类为每个线程生成唯一标识。一个线程的id是它第一次调用ThreadId.get()方法指定的。

  1. package com.cjs.example;import java.util.concurrent.atomic.AtomicInteger;public class ThreadId {private static final AtomicInteger nextId = new AtomicInteger(0);private static final ThreadLocal<Integer> threadId = new ThreadLocal<Integer>() {
  2.         @Overrideprotected Integer initialValue() {return nextId.getAndIncrement();
  3.         }
  4.     };public static int get() {return threadId.get();
  5.     }public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread(new Runnable() {
  6.                 @Overridepublic void run() {
  7.                     System.out.println(Thread.currentThread().getId());
  8.                 }
  9.             }).start();
  10.         }
  11.     }
  12. }

2.  ThreadLocal主要操作

  1. /**
  2.  * 返回当前线程对ThreadLocal变量的&ldquo;初始值&rdquo;
  3.  * 这个方法将在线程第一次访问变量(通过调用get方法)时被调用,如果之前已经调用过了就不会再调了
  4.  *
  5.  * @return the initial value for this thread-local */protected T initialValue() {return null;
  6. }/**
  7.  * 设置当前线程的ThreadLocal变量的副本为指定的值
  8.  *
  9.  * @param value the value to be stored in the current thread's copy of this thread-local. */public void set(T value) {
  10.     Thread t = Thread.currentThread();
  11.     ThreadLocalMap map = getMap(t);if (map != null)
  12.         map.set(this, value);elsecreateMap(t, value);
  13. }/**
  14.  * 返回当前线程的ThreadLocal变量副本的值
  15.  *
  16.  * @return the current thread's value of this thread-local */public T get() {
  17.     Thread t = Thread.currentThread();
  18.     ThreadLocalMap map = getMap(t);if (map != null) {
  19.         ThreadLocalMap.Entry e = map.getEntry(this);if (!= null) {
  20.             @SuppressWarnings("unchecked")
  21.             T result = (T)e.value;return result;
  22.         }
  23.     }return setInitialValue();
  24. }/**
  25.  * 删除当前线程的ThreadLocal变量副本的值 */public void remove() {
  26.     ThreadLocalMap m = getMap(Thread.currentThread());if (!= null)
  27.         m.remove(this);
  28. }

3.  阅读源码

3.1.  set方法

可以看到,ThreadLocalMap底层是一个数组,数组中元素类型是Entry类型

set操作是向当前线程的ThreadLocal.ThreadLocalMap类型的成员变量threadLocals中设置值,key是this,value是我们指定的值

注意,这里传的this代表的是那个ThreadLocal类型的变量(或者说叫对象)

也就是说,每个线程都维护了一个ThreadLocal.ThreadLocalMap类型的对象,而set操作其实就是以ThreadLocal变量为key,以我们指定的值为value,最后将这个键值对封装成Entry对象放到该线程的ThreadLocal.ThreadLocalMap对象中。每个ThreadLocal变量在该线程中都是ThreadLocal.ThreadLocalMap对象中的一个Entry。既然每个ThreadLocal变量都对应ThreadLocal.ThreadLocalMap中的一个元素,那么就可以对这些元素进行读写删除操作。

3.2.  get方法

get()方法就是从当前线程的ThreadLocal.ThreadLocalMap对象中取出对应的ThreadLocal变量所对应的值

同理,remove()方法就是清除这个值

用图形表示的话,大概是这样的:

或者是这样的:

4.  ThreadLocal使用场景

  1. 在线程生命周期内传值

最后,一切都归功于ThreadLocalMap

 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号