ThreadLocal的理解

本文详细介绍了ThreadLocal的概念及其在多线程环境下如何为每个线程提供独立的变量副本,避免了线程间的变量共享问题。同时对比了ThreadLocal与传统同步机制的区别。

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

ThreadLocal是什么
    ThreadLocal,顾名思义,它不是一个线程,而是线程的一个本地化对象。当工作于多线程中的对象使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程分配一个独立的变量副本。所以每一个线程都可以独立改变自己的副本,而不会影响其他线程所对应的副本。从线程的角度看,这个变量就像是线程的本地变量,这也是类名中"Local"索要表达的意思

ThreadLocal的接口方法
    void set(T value);
    T get();
    protected T initialValue();
    返回该线程局部变量的初始值,改方法时一个protected的方法,显然是为了让子类覆盖而设计的。这个方法时一个延迟调用方法,在线程第一次调用get()或set(T value)ThreadLocal默认实现直接返回一个null


ThreadLocal是如何做到为每一个线程维护一份独立的副本变量呢?其实实现思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应的变量副本,下面是一个简单版本的ThreadLocal

import java.util.HashMap;
import java.util.Map;

public class ThreadLocalSimple<T> {
	
	private Map<Thread,T> threadLocalMap = new HashMap<>(); 
	
	public void set(T object) {
		threadLocalMap.put(Thread.currentThread(), object);
	}
	
	public T get() {
		Thread currentThread = Thread.currentThread();
		T object = threadLocalMap.get(currentThread);
		if(object == null){
			object = initialValue();
			threadLocalMap.put(currentThread, object);
		}
		return object;
	} 
	
	public void remove() {
		threadLocalMap.remove(Thread.currentThread());
	}
	
	protected T initialValue() {
		return null;
	}
}

一个ThreadLocal实例,通过这个实例来感受一下ThreadLocal的具体用法

public class SequenceNumber {

	public static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){

		@Override
		protected Integer initialValue() {
			return 0;
		}
	};
	
	public int getNextNum() {
		seqNum.set(seqNum.get()+1);
		return seqNum.get();
	}
	
	public static void main(String[] args) {
		SequenceNumber sn = new SequenceNumber();
		TestClient task = new TestClient(sn);
		Thread t1 = new Thread(task);
		Thread t2 = new Thread(task);
		Thread t3 = new Thread(task);
		t1.start();
		t2.start();
		t3.start();
	}
	
	private static class TestClient implements Runnable {
		private SequenceNumber sn;
		public TestClient(SequenceNumber sn) {
			this.sn = sn;
		}
		@Override
		public void run() {
			for(int i=0;i<3;i++) {
				System.out.println("thread["+Thread.currentThread().getName()+"]sn["+sn.getNextNum()+"]");
			}
		}
		
	}
}
//output

thread[Thread-2]sn[1]
thread[Thread-0]sn[1]
thread[Thread-1]sn[1]
thread[Thread-0]sn[2]
thread[Thread-2]sn[2]
thread[Thread-0]sn[3]
thread[Thread-1]sn[2]
thread[Thread-2]sn[3]
thread[Thread-1]sn[3]

通过输出可见三个线程共享SequenceNumber变量,但没有相互影响自己的计数器


ThreadLocal与Thread同步机制的比较

    对于多线程资源共享问题,同步机制采用了"以时间换空间"的方式:访问串行化,对象共享化。而ThreadLocal采用了"以空间换时间"的方式:访问并行化,对象独享化。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值