ThreadLocal的介绍与运用

ThreadLocal全面解析学习目标

  • 了解ThreadLocal的介绍
  • 掌握ThreadLocal的运用场景
  • 了解ThreadLocal的内部结构
  • 了解ThreadLocal的核心方法源码
  • 了解ThreadLocalMap的源码
1. ThreadLocal介绍1.1 官方介绍/** * This class provides thread-local variables.These variables differ from * their normal counterparts in that each thread that accesses one (via its * {@code get} or {@code set} method) has its own, independently initialized * copy of the variable.{@code ThreadLocal} instances are typically private * static fields in classes that wish to associate state with a thread (e.g., * a user ID or Transaction ID). * * <p>For example, the class below generates unique identifiers local to each * thread. * A thread's id is assigned the first time it invokes {@code ThreadId.get()} * and remains unchanged on subsequent calls. * <pre> * import java.util.concurrent.atomic.AtomicInteger; * * public class ThreadId { *// Atomic integer containing the next thread ID to be assigned *private static final AtomicInteger nextId = new AtomicInteger(0); * *// Thread local variable containing each thread's ID *private static final ThreadLocal&lt;Integer&gt; threadId = *new ThreadLocal&lt;Integer&gt;() { *@Override protected Integer initialValue() { *return nextId.getAndIncrement(); *} *}; * *// Returns the current thread's unique ID, assigning it if necessary *public static int get() { *return threadId.get(); *} * } * </pre> * <p>Each thread holds an implicit reference to its copy of a thread-local * variable as long as the thread is alive and the {@code ThreadLocal} * instance is accessible; after a thread goes away, all of its copies of * thread-local instances are subject to garbage collection (unless other * references to these copies exist). * * @authorJosh Bloch and Doug Lea * @since1.2 */public class ThreadLocal<T> {...? 从Java官方文档中的描述:ThreadLocal类用来提供线程内部的局部变量 。这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量 。ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程上下文 。
我们可以得知 ThreadLocal 的作用是:提供线程内的局部变量,不同的线程之间不会相互干扰,这种变量在线程的生命周期内起作用 , 减少同一个线程内多个函数或组件之间一些公共变量传递的复杂度 。总结:1. 线程并发: 在多线程并发的场景下2. 传递数据: 我们可以通过ThreadLocal在同一线程 , 不同组件中传递公共变量3. 线程隔离: 每个线程的变量都是独立的 , 不会相互影响1.2 基本使用1.2.1 常用方法? 在使用之前,我们先来认识几个ThreadLocal的常用方法
方法声明描述ThreadLocal()创建ThreadLocal对象public void set( T value)设置当前线程绑定的局部变量public T get()获取当前线程绑定的局部变量public void remove()移除当前线程绑定的局部变量1.2.2 使用案例我们来看下面这个案例public class MyDemo {private String content;private String getContent() {return content;}private void setContent(String content) {this.content = content;}public static void main(String[] args) {MyDemo demo = new MyDemo();for (int i = 0; i < 5; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {demo.setContent(Thread.currentThread().getName() + "的数据");System.out.println("-----------------------");System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());}});thread.setName("线程" + i);thread.start();}}}打印结果:
ThreadLocal的介绍与运用

文章插图
? 从结果可以看出多个线程在访问同一个变量的时候出现的异常,线程间的数据没有隔离 。下面我们来看下采用 ThreadLocal 的方式来解决这个问题的例子 。
public class MyDemo {private static ThreadLocal<String> tl = new ThreadLocal<>();private String content;private String getContent() {return tl.get();}private void setContent(String content) {tl.set(content);}public static void main(String[] args) {MyDemo demo = new MyDemo();for (int i = 0; i < 5; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {demo.setContent(Thread.currentThread().getName() + "的数据");System.out.println("-----------------------");System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());}});thread.setName("线程" + i);thread.start();}}}打印结果:
?
ThreadLocal的介绍与运用

文章插图
从结果来看,这样很好的解决了多线程之间数据隔离的问题,十分方便 。
1.3 ThreadLocal类与synchronized关键字1.3.1 synchronized同步方式? 这里可能有的朋友会觉得在上述例子中我们完全可以通过加锁来实现这个功能 。我们首先来看一下用synchronized代码块实现的效果:

推荐阅读