1、ThreadLocal介绍:
多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线程安全性。ThreadLocal是除了加锁这种同步方式之外的一种保证一种规避多线程访问出现线程不安全的方法,当我们在创建一个变量后,如果每个线程对其进行访问的时候访问的都是线程自己的变量这样就不会存在线程不安全问题。
- ThreadLocal使用demo:
public class ThreadLoaclDemo {
private static ThreadLocal<String> counterHolder =
new ThreadLocal<>();
static void print(String str){
System.out.println(str+" : "+counterHolder.get());
//清楚本地内存中的本地内存
counterHolder.remove();
}
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
counterHolder.set("fun-1");
print("thread-1");
System.out.println("after remove : "+counterHolder.get());
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
counterHolder.set("fun-2");
print("thread-2");
System.out.println("after remove : "+counterHolder.get());
}
});
t1.start();
t2.start();
}
}
- ThreadLocal的set方法源码
1 public void set(T value) {
2 //(1)获取当前线程(调用者线程)
3 Thread t = Thread.currentThread();
4 //(2)以当前线程作为key值,去查找对应的线程变量,找到对应的map
5 ThreadLocalMap map = getMap(t);
6 //(3)如果map不为null,就直接添加本地变量,key为当前定义的ThreadLocal变量的this引用,值为添加的本地变量值
7 if (map != null)
8 map.set(this, value);
9 //(4)如果map为null,说明首次添加,需要首先创建出对应的map
10 else
11 createMap(t, value);
12 }
- ThreadLocalt的get方法源码
public T get() {
2 //(1)获取当前线程
3 Thread t = Thread.currentThread();
4 //(2)获取当前线程的threadLocals变量
5 ThreadLocalMap map = getMap(t);
6 //(3)如果threadLocals变量不为null,就可以在map中查找到本地变量的值
7 if (map != null) {
8 ThreadLocalMap.Entry e = map.getEntry(this);
9 if (e != null) {
10 @SuppressWarnings("unchecked")
11 T result = (T)e.value;
12 return result;
13 }
14 }
15 //(4)执行到此处,threadLocals为null,调用该更改初始化当前线程的threadLocals变量
16 return setInitialValue();
17 }
18
19 private T setInitialValue() {
20 //protected T initialValue() {return null;}
21 T value = initialValue();
22 //获取当前线程
23 Thread t = Thread.currentThread();
24 //以当前线程作为key值,去查找对应的线程变量,找到对应的map
25 ThreadLocalMap map = getMap(t);
26 //如果map不为null,就直接添加本地变量,key为当前线程,值为添加的本地变量值
27 if (map != null)
28 map.set(this, value);
29 //如果map为null,说明首次添加,需要首先创建出对应的map
30 else
31 createMap(t, value);
32 return value;
33 }
- ThreadLocal的remove方法的源码
public void remove() {
2 //获取当前线程绑定的threadLocals
3 ThreadLocalMap m = getMap(Thread.currentThread());
4 //如果map不为null,就移除当前线程中指定ThreadLocal实例的本地变量
5 if (m != null)
6 m.remove(this);
7 }
2、ThreadLocal不支持继承性
同一个ThreadLocal变量在父线程中被设置值后,在子线程中是获取不到的。(threadLocals中为当前调用线程对应的本地变量,所以二者自然是不能共享的)。但是InheritableThreadLocal可以做到这个功能。
3、ThreadLocl内存泄漏问题
THreadLocalMap中的Entry的key使用的是ThreadLocal对象的弱引用,在没有其他地方对ThreadLoca依赖,ThreadLocalMap中的ThreadLocal对象就会被回收掉,但是对应的不会被回收,这个时候Map中就可能存在key为null但是value不为null的项,这需要实际的时候使用完毕及时调用remove方法避免内存泄漏。