再谈 ThreadLocal

几年前我曾经写过两篇关于 ThreadLocal 的文章,分别是ThreadLocal类之简单理解和ThreadLocal类之简单应用示例,不过限于当时的水平,有些问题并没有说的很明白,所以今天再写一篇文章,重新说说这个类。 我们首先看一个例子: package cn.bridgeli.demo; /** * @author BridgeLi * @date 2021/4/21 11:02 */ public class User { String name = "Denny"; } 然后我们有一个操作: package cn.bridgeli.demo; import org.junit.Test; /** * @author BridgeLi * @date 2021/4/21 10:28 */ public class ThreadTest { private User user = new User(); @Test public void testThreadLocal() { new Thread(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(user.name); }).start(); new Thread(() -> user.name = "BridgeLi").start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } 这个时候我们就知道一定会有线程安全问题,所以我们怎么解决这个问题呢?就是 ThreadLocal,请看下面: ...

April 22, 2021 · 3 min · 478 words · Bridge Li

ThreadLocal类之简单理解

当年实习的时候,当时公司一个相当有经验的工程师zeak带我们,从他那第一次听说了ThreadLocal类,但由于自己基础薄弱,没有理解到底怎么回事,工作中也没有用过,就一直没有太放在心上,刚好这一段时间不太忙,仔细玩了一下,欢迎高手批评。 ThreadLocal,线程本地变量。他为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。简单理解就是,对于非线程安全的变量在线程内部共享不用每次都new,是一种空间换时间的做法。ThreadLocal类提供的几个方法: public T get() { } public void set(T value) { } public void remove() { } protected T initialValue() { } 看名字就知道这些方法是干嘛的了,下面我们来看一下ThreadLocal类是如何为每个线程创建一个变量的副本的。首先是get方法的实现: 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(t)方法获取到一个map,map的类型为ThreadLocalMap。然后接着下面获取到<key,value>键值对,注意这里获取键值对传进去的是 this,而不是当前线程t。如果获取成功,则返回value值。如果map为空,则调用setInitialValue方法返回value。那么getMap方法中又做了什么呢? ThreadLocalMap getMap(Thread t) { return t.threadLocals; } 原来是返回当前线程t中的一个成员变量threadLocals,而threadLocals则是: ThreadLocal.ThreadLocalMap threadLocals = null; 那就看看ThreadLocalMap的实现了: ...

June 11, 2017 · 2 min · 222 words · Bridge Li