关于多线程并发安全控制,我们第一反应都是用锁,但是无论是哪种锁,多多少少都对性能都有一定得影响。那么有什么方法既能保证共享资源的线程安全,又能避免锁呢?答案就是ThreadLocal。ThreadLocal可以解释成线程的局部变量,即每个线程都有变量的副本,一个线程对变量的访问都是对线程自己变量的访问,对其他线程并无影响,也就保证了对于共享资源的线程安全,又避免用锁。
ThreadLocal的基本使用
创建一个ThreadLocal对象:
public class ThreadLocalTest {private ThreadLocal<Integer> localInt = new ThreadLocal<>();public void testLocal(){for (int i = 0; i < 10; i++) {final int value = i * 2;new Thread(new Runnable() {@Overridepublic void run() {localInt.set(value);System.out.println(Thread.currentThread().getName() + ":" +localInt.get());localInt.remove();}}).start();}}public static void main(String[] args) {ThreadLocalTest localTest = new ThreadLocalTest();localTest.testLocal();}}
ThreadLocal的构造方法无参数,由于ThreadLocal是一个泛型类,这里指定了localInt的类型为整数。ThreadLocal常用的方法有:
- set(obj):向当前线程中存储数据
- get():获取当前线程中的数据
- remove():删除当前线程中的数据
由于ThreadLocal里设置的值,只有当前线程自己看得见,这意味着你不可能通过其他线程为它初始化值。为了弥补这一点,ThreadLocal提供了一个withInitial()方法统一初始化所有线程的ThreadLocal的值:
private ThreadLocal<Integer> localInt = ThreadLocal.withInitial(() -> 6);
ThreadLocal的实现原理
ThreadLocal可以做到变量的线程隔离(线程只可见自己的变量),那么它是怎么做到的呢?我们先从ThreadLocal的set方法开始入手:
public void set(T value) {//获取当前线程Thread t = Thread.currentThread();//获取ThreadLocalMapThreadLocalMap map = getMap(t);if (map != null)map.set(this, value); //就是map的设值elsecreateMap(t, value); //map为空先创建再设值}
从上面的代码我们可以知道ThreadLocalMap是实现的关键。看一下getMap(t) 的实现:
ThreadLocalMap getMap(Thread t) {return t.threadLocals;}
很简单,就是从当前线程中获取ThreadLocalMap。到这里我们可以大概猜测到,所谓的ThreadLocal变量就是保存在每个线程的map中的。这个map就是Thread对象中的threadLocals字段:
public class Thread implements Runnable {.../* ThreadLocal values pertaining to this thread. This map is maintained* by the ThreadLocal class. */ThreadLocal.ThreadLocalMap threadLocals = null;...}
关于ThreadLocalMap
未完待续…
