1.为什么使用ThreadLocal?
当我们进行java的相关操作的时候,有时候并不是想 这个资源进行共享 只是有的时候,一些代码导致这个资源得到共享了,那么就可以通过ThreadLocal来进行密封操作这个资源,然后为每一次访问此资源的线程都创建一个副本,有人会问那么为什么不适用同步块呢,因为,同步块解决线程安全问题的时候,其他线程都会排队等待,这就导致了时间上耗费过多的问题,但是他每次知识访问的同一个资源,节省了内存。通过同步块来解决线程安全问题,会比ThreadLocal慢150倍左右, 用ThreadLocal来解决的时候,是为每个变量创建一个副本,节约了排队等待的时间,但是耗费了内存
还可以通过其他的方式来避免,比如说当属性私有化的时候只提供set方法,没有get方法 就是只读,那么就不会有线程安全问题了,还有就是不提供成员变量,再有就是无状态对象,就是在对象之中的方法没有 设置值。
2.ThreadLocal的山寨,与应用场景
其实ThreadLocal有用的方法只有三个,set(对象),get(),remove(),并且一个ThreadLocal里面只能有一个对象
比如:
public class TestThreadLocal {
private static ThreadLocal<Integer> tl = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
// TODO Auto-generated method stub
return 0;//初始化方法,当调用get方法为空的时候,这个方法会自动为ThreadLocal设置值
}
};
public static Integer bb(){
tl.set(tl.get()+1);
return tl.get();
}
@Test
public void test(){
new Thread(){
public void run(){
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+" "+TestThreadLocal.bb());
}
}
}.start();
new Thread(){
public void run(){
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+" "+TestThreadLocal.bb());
}
}
}.start();
}
}
运行结果如下
Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-0 5
Thread-0 6
Thread-0 7
Thread-0 8
Thread-0 9
Thread-0 10
Thread-1 1
Thread-1 2
Thread-1 3
Thread-1 4
Thread-1 5
Thread-1 6
Thread-1 7
Thread-1 8
Thread-1 9
Thread-1 10
大家可以看到,两个线程之间并没有对Integer产生影响,而是每一个线程都得到了自己的副本。说了这么多,可能还是有一些迷糊,现在我山寨一下ThreadLocal的
实现,因为源码比较难懂,这里简单的山寨,相信,看了这里,你在看一些大神的博客分析这里的源码会理解很多,其实ThreadLocal本质来说是一个map类型的,
内部的数据结构就是map ,山寨完我用一张图解释一下上面的过程,就容易理解了
山寨开始
class ThreadLocal<T>{
private Map<Thread,T> map = new HashMap<Thread,T>();
public void set(T data){
map.put(Thread.currentThread(),data);
}
public T get(){
return map.get(Thread.currentThread());
}
public void remove(){
map.remove(Thread.currentThread());
}
}
ThreadLocal时以当前线程做key,以要保护的变量做值,当一个线程向要得到值的时候,如果不是当前线程,那么就得不到这个变量,因为他不是这个value的值,只能是自己在创建一个副本。保存自己作为key,这样这个value就归自己所有了。与其他线程互相不干扰
好了现在用一张图,来解释上面的代码
这里只是解释了其中一个循环所做的事,但是见微知著,相信大家都已经理解了。
3.那么ThreadLocal都应用在什么上面呢?
主要是数据库和一些其他非共享变量上面。
因为数据库连接不能是一个线程正在open,一个close吧(正常情况),还有就是用户操作数据库,不能排队等待吧(同步块),这样用户体验度会很差的。当然了,除了用这种方式,还可以用线程池来解决,好了吗,这就是全部内容,不知道大家懂了吗。如果我说的哪里有毛病,欢迎来批评指正。