ThreadLocal的理解

Java中的ThreadLocal类允许我们创建只能被同一个线程读写的变量。因此,如果一段代码含有一个ThreadLocal变量的引用,即使两个线程同时执行这段代码,它们也无法访问到对方的ThreadLocal变量。

The ThreadLocal class in Java enables you to create variables that can only be read and written by the same thread. Thus, even if two threads are executing the same code, and the code has a reference to a ThreadLocal variable, then the two threads cannot see each other's ThreadLocal variables.

解析ThreadLocal类

  • ThreadLocal中 get()方法的实现
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}

判断当前线程,通过getMap 方法返回一个ThreadLocalMap 。

判断map 是否为null ,如果存在的话,就从ThreadLocalMap中获取对应的value,不存在调用setInitialValue方法。

来看看getMap方法的实现。

    /**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}

getMap传入当前的线程返回一个threadLocals,成员变量threadLocals是什么?

 /* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;

再来看看 ThreadLocalMap ,通过map来实现key-value 的存储。

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;
}
} /**
* Set the value associated with key.
*
* @param key the thread local object
* @param value the value to be set
*/
private void set(ThreadLocal key, Object value) { // We don't use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not. Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal k = e.get(); if (k == key) {
e.value = value;
return;
} if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
} tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
  • ThreadLocal中set()方法的实现
 /**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}

拷贝一个当前的线程,和上面的get方法对应起来看。这里也是get来进行判断。

代码测试


public class ThreadLocalTest implements Runnable { private ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(); @Override
public void run() {
threadLocal.set((int) (Math.random() * 100D)); try {
Thread.sleep(2000);
} catch (InterruptedException e) {
} System.out.println(threadLocal.get());
} public static void main(String[] args) throws Exception {
ThreadLocalTest sharedRunnableInstance = new ThreadLocalTest(); Thread thread1 = new Thread(sharedRunnableInstance);
Thread thread2 = new Thread(sharedRunnableInstance); thread1.start();
thread2.start(); thread1.join(); // wait for thread 1 to terminate
thread2.join(); // wait for thread 2 to terminate
}
}

总结

上面的例子,将ThreadLocalTest 实例传递給两个线程,执行run 方法这两个线程分别保存了不同的数据。如果不是访问ThreadLocal对象,第2个线程会覆盖掉第1个线程的值。ThreadLocal不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象。

ThreadLocal使用场景,多线程实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。 ThreadLocal 也常用数据库连接操作。

参考

ThreadLocal 简述的更多相关文章

  1. java并发:线程同步机制之ThreadLocal

    1.简述ThreadLocal ThreadLocal实例通常作为静态的私有的(private static)字段出现在一个类中,这个类用来关联一个线程.ThreadLocal是一个线程级别的局部变量 ...

  2. ThreadLocal父子线程传递实现方案

    介绍InheritableThreadLocal之前,假设对 ThreadLocal 已经有了一定的理解,比如基本概念,原理,如果没有,可以参考:ThreadLocal源码分析解密.在讲解之前我们先列 ...

  3. java引用类型简述

    主要内容: 1.引用类型简述 2.对象的可达性 3.软引用的垃圾回收分析 4.WeakHashMap分析 5.ThreadLocal内存泄漏分析 1.引用类型简述 在Java语言中除了基本数据类型外, ...

  4. 【原理】Java的ThreadLocal实现原理浅读

    当前线程的值传递,ThreadLocal 通过ThreadLocal设值,在线程内可获取,即时获取值时在其它Class或其它Method. public class BasicUsage { priv ...

  5. JVM参数简述

    java虚拟机启动时会带有很多的启动参数,Java命令本身就是一个多参数的启动命令.那么具体JVM启动包含哪些参数呢?这篇文章针对java8的情况做一篇汇总解读,包含大多数常见和不常见的命令参数,过于 ...

  6. Netty源码分析第5章(ByteBuf)---->第4节: PooledByteBufAllocator简述

    Netty源码分析第五章: ByteBuf 第四节: PooledByteBufAllocator简述 上一小节简单介绍了ByteBufAllocator以及其子类UnPooledByteBufAll ...

  7. ThreadLocal 从源码角度简单分析

    目录 ThreadLcoal源码浅析 ThreadLocal的垃圾回收 Java引用 ThreadLocal的回收 各线程中threadLocalMap的回收 内存泄露问题 总结 参考 ThreadL ...

  8. Java线程之ThreadLocal

    翻译:https://www.journaldev.com/1076/java-threadlocal-example?utm_source=website&utm_medium=sideba ...

  9. ThreadLocal是什么?使用场景有哪些?

    什么是ThreadLocal? ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本. 测试代码: package ...

随机推荐

  1. Java Web学习路线图

    三张Java Web完整学习路线图,阶段一和JavaSE部分可不学

  2. Jfinal——实践出真知

    什么是Jfinal? JFinal 是基于 Java 语言的极速 WEB + ORM 框架,其核心设计目标是开发迅速.代码量少.学习简单.功能强大.轻量级.易扩展.Restful.在拥有Java语言所 ...

  3. curl说明

    https://baike.baidu.com/item/curl/10098606?fr=aladdin curl是利用URL语法在命令行方式下工作的开源文件传输工具.它被广泛应用在Unix.多种L ...

  4. ThinkPhp5.0_文件上传

    ===================================================================== 路径: F:\wamp\www\public\uploads ...

  5. React Native学习(八)—— 对接七鱼客服

    本文基于React Native 0.52 Demo上传到Git了,有需要可以看看,写了新内容会上传的.Git地址 https://github.com/gingerJY/React-Native-D ...

  6. wigs的理解和应用

    1. 首先了解下,Web应用的本质,大体如下: 1.浏览器发送一个HTTP请求: 2.服务器收到请求,生成一个HTML文档: 3.服务器把HTML文档作为HTTP响应的Body发送给浏览器: 4.浏览 ...

  7. greedy算法(python版)

    greedy算法的核心思想是首先计算覆盖面大的部分,然后依次寻找其他覆盖面最大的部分.该算法的使用场景就像他的名字一样,当符合贪婪属性的时候就可以考虑. states_needed = set(['北 ...

  8. php中HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR的使用

    1.REMOTE_ADDR:浏览当前页面的用户计算机的ip地址2.HTTP_X_FORWARDED_FOR: 浏览当前页面的用户计算机的网关3.HTTP_CLIENT_IP:客户端的ip 在PHP 中 ...

  9. redhat linux/CentOS 6/7 如何关闭防火墙?

    redhat linux/CentOS 6/7 如何关闭防火墙?关闭防火墙iptables的具体命令如下: 临时性的完全关闭防火墙,可以不重启机器(但是重启服务器后iptables防火墙服务会自动随系 ...

  10. Java数据结构和算法(十四)——堆

    在Java数据结构和算法(五)——队列中我们介绍了优先级队列,优先级队列是一种抽象数据类型(ADT),它提供了删除最大(或最小)关键字值的数据项的方法,插入数据项的方法,优先级队列可以用有序数组来实现 ...