从上一篇对于ThreadLocal的分析来看,可以得出结论:ThreadLocal不是用来解决共享对象的多线程访问问题的,通过ThreadLocal的set()方法设置到线程的ThreadLocal.ThreadLocalMap里的是是线程自己要存储的对象,其他线程不需要去访问,也是访问不到的。各个线程中的ThreadLocal.ThreadLocalMap以及ThreadLocal.ThreadLocal中的值都是不同的对象。
至于为什么要使用ThreadLocal,不妨这么考虑这个问题。Java Web中,写一个Servlet:
public class Servlet extendsHttpServlet
{protected voiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException
{this.doGet(request, response);
}protected voiddoPost(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException
{
}
}
我在一个普通JavaBean内想拿到这个HttpServletRequest,但是无法通过参数传递的方式:
public classOperateRequest
{publicString operateRequest()
{return null;
}
}
这时候怎么办?第一个解决方案,Servlet类中定义一个全局的HttpServletRequest,至于怎么定义就随便了,可以定义成静态的,也可以定义成非静态的但是对外提供setter/getter,然后operateRequest()方法每次都取这个全局的HttpServletRequest就可以了。
不否认,这是一种可行的解决方案,但是这种解决方案有一个很大的缺点:竞争。既然HttpServletRequest是全局的,那势必要引入同步机制来保证线程安全性,引入同步机制意味着牺牲响应给用户的时间----这在注重与用户之间响应的Java Web中是难以容忍的。
所以,我们引入ThreadLocal,既然ThreadLocal.ThreadLocalMap是线程独有的,别的线程访问不了也没必要访问,那我们通过ThreadLocal把HttpServletRequest设置到线程的ThreadLocal.ThreadLocalMap里面去不就好了?这样,在一次请求中哪里需要用到HttpServletRequest,就使用ThreadLocal的get()方法就把这个HttpServletRequest给取出来了,是不是一个很好的解决方案呢?
在这里我原先也写了篇笔记 ,可以先看看java 中的 ThreadLocal
ThreadLocal使用
忘记上面那个复杂的问题,我们来看一下ThreadLocal的简单使用,首先ThreadLocal肯定是全局共享的:
public classTools
{public static ThreadLocal t1 = new ThreadLocal();
}
写一个线程往ThreadLocal里面塞值:
public class ThreadLocalThread extendsThread
{private static AtomicInteger ai = newAtomicInteger();publicThreadLocalThread(String name)
{super(name);
}public voidrun()
{try{for (int i = 0; i < 3; i++)
{
Tools.t1.set(ai.addAndGet(1) + "");
System.out.println(this.getName() + " get value--->" +Tools.t1.get());
Thread.sleep(200);
}
}catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
写个main函数,启动三个ThreadLocalThread:
public static void main(String[] args) throwsException
{
ThreadLocalThread a= new ThreadLocalThread("ThreadA");
ThreadLocalThread b= new ThreadLocalThread("ThreadB");
ThreadLocalThread c= new ThreadLocalThread("ThreadC");
a.start();
b.start();
c.start();
}
看一下运行结果:
ThreadA get value--->1ThreadC get value--->2ThreadB get value--->3ThreadB get value--->4ThreadC get value--->6ThreadA get value--->5ThreadC get value--->8ThreadA get value--->7ThreadB get value--->9
看到每个线程的里都有自己的String,并且互不影响----因为绝对不可能出现数字重复的情况。用一个ThreadLocal也可以多次set一个数据,set仅仅表示的是线程的ThreadLocal.ThreadLocalMap中table的某一位置的value被覆盖成你最新设置的那个数据而已,对于同一个ThreadLocal对象而言,set后,table中绝不会多出一个数据,这里要注意,如果第一次没有给ThreadLocal设置值的话,是会返回null的。
ThreadLocal.get 返回null解决
上面的对threadlocal 进行了初始化,从而没有进入 判断为null的if分支
InheritableThreadLocal的使用,值继承,继承父线程InheritableThreadLocal的值
从上面可以看得出来,使用InheritableThreadLocal子线程会自动继承父线程的InheritableThreadLocal值
InheritableThreadLocal值继承再修改
跟上面一样,继承childValue可以在子线程使用InheritableThreadLocal自动调用这个方法初始化子线程的值,记住只是初始化,也就是只执行一次,当父线程再次修改InheritableThreadLocal的值时,子线程取的就是父线程修改后的值了