标签:
这个类在java1.2中就出现了,线程独有的变量(每个线程都有一份变量),使用它的好处之一就是可以少传许多参数。
在哪里用到它呢?有连接池的地方就有它的身影,连接池包括数据库连接池,网络连接池等。
import java.util.UUID; class Factory { static ThreadLocal<String> connection=new ThreadLocal<>(); static String getConnection() { String s=connection.get(); if (s == null) { connection.set(UUID.randomUUID().toString()); } return connection.get(); } } public class TestThreadLocal { static void f() { String s = Factory.getConnection(); System.out.println("f :" + s); g(); } static void g() { String s = Factory.getConnection(); System.out.println("g :" + s); } public static void main(String[] args) { new Thread(() -> f()).start(); new Thread(() -> f()).start(); } }
输出结果:
f :6c71fba2-8fd6-4de9-88f9-69023290e213
f :c315c241-b379-446d-8159-dc758f020a80
g :c315c241-b379-446d-8159-dc758f020a80
g :6c71fba2-8fd6-4de9-88f9-69023290e213
ThreadLocal<String>connection这个变量其实就是一个马甲,它是唯一的一份(因为它是静态的呀)。这唯一的一份就相当于一个线程大管家,它负责去访问当前线程。请看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) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
第一步,它会去获取当前线程t
第二步,通过当前线程t获取ThreadLocalMap对象map
第三步,如果没有map,那就给当前线程new出来一个并赋上初值(通过setInitialValue来实现);如果已经存在,那就读取之。
ThreadLocalMap这个类是一个内部静态类,全名是:ThreadLocal.ThreadLocalMap,其内部元素的键就是this(也就是ThreadLocal实例,即上例中的connection变量),值是Object类型的实例。
Entry(ThreadLocal<?> k, Object v)
Thread这个类大名鼎鼎,它内部有一个成员变量:
ThreadLocal.ThreadLocalMap threadLocals = null;
上例中,线程1和线程2各有一份ThreadLocalMap成员变量threadLocals,这两个threadLocals中都有同一份键:connection,但是它们的值不是同一份。
每一个线程都维持一份ThreadLocalMap threadLocals,ThreadLocal这个大管家负责访问当前线程对象的threadLocals变量
可见,ThreadLocal机制是纯java代码,没有底层实现,我们自己也是可以实现的,这是一种巧妙地机制。
ThreadLocal和ThreadLocalMap在同一个文件里面并且ThreadLocalMap是ThreadLocal的静态内部类,然后Thread又有ThreadLocalMap的成员变量,最后ThreadLocal变量作为一个大管家去访问ThreadLocalMap。这个API设计的真是合理,就该这么整啊!实现起来简简单单,却带来许多便利。
标签:
原文地址:http://www.cnblogs.com/weidiao/p/5426438.html