0
点赞
收藏
分享

微信扫一扫

图解ThreadLocal核心原理


线程安全问题的本质:对“共享资源”,“并发操作”导致的数据不一致问题。注意两个关键字:“共享资源”,“并发操作”

图解ThreadLocal核心原理_互斥

通常解决线程安全问题通过加锁,互斥访问共享资源

而ThreadLocal换了个思路解决问题,不访问“共享资源”,每个线程都访问自己的资源

简单用一下TheadLocal

public class ThreadLocalTest {
public static void simpleUseThreadLocal(){
ThreadLocal<Integer> threadLocalObj = new ThreadLocal();// 1
threadLocalObj.set(1);// 2
System.out.println(Thread.currentThread().getName()+":"+threadLocalObj.get());
}
public static void main(String[] args) throws InterruptedException {
simpleUseThreadLocal();
}
}
//输出, main:1

看看ThreadLocal相关源码

public class ThreadLocal<T> {
public ThreadLocal() {
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
static class ThreadLocalMap {

}
}
public class Thread implements Runnable {
ThreadLocal.ThreadLocalMap threadLocals = null;
....
}

本程序的执行时,main线程的内存示意图

图解ThreadLocal核心原理_互斥_02

其实ThreadLocal的原理很简单,执行ThreadLocal的set方法时,可以获取当前的执行线程(​​Thread.currentThread()​​),线程下放入一个Map,Map中放入你的value,key为ThreadLocal对象。

get方法同理:获取执行线程,从执行线程的Map中get出key为“ThreadLocal对象”的value

1、ThreadLocal#set()方法源码分析

图解ThreadLocal核心原理_线程安全_03

2、ThreadLocal#get()方法源码分析

图解ThreadLocal核心原理_线程安全_04

3、RocketMQ应用案例

在RocketMQ中,应用程序使用RocketMQ的客户端向Broker发送消息时,为了保证Broker中的每个MessageQueue的负载均衡,客户端应该均衡的从选择MessageQueue进行发送

多线程并发使用一个生产者(DefaultMQProducer)不断地发送消息时,如何均衡的从多个MessageQueue中选择一个进行发送呢?

图解ThreadLocal核心原理_互斥_05


RocketMQ就是使用的ThreadLocal,每个线程维护一个index,获取一个MessageQueue信息后index=index+1,这样每个线程就可以依次选择MessageQueue进行发送消息了。

如果不使用ThreadLocal,如何依次选择MessageQueue呢?可能就需要生产者维护一个index,然后多个线程同步互斥访问这个index了

4、总结

通过案例我们知道,在多线程并发编程时,为了保证线程安全,我们除了可以同步访问共享资源,还有另外一个选项:是不是可以访问共享资源呢?

图解ThreadLocal核心原理_访问共享_06

特定的场景下选择ThreadLocal,没有互斥访问,在一定程度上可以提升程序的性能


举报

相关推荐

0 条评论