Java多线程10:ThreadLocal的作用及使用详解编程语言

ThreadLocal的作用

从上一篇对于ThreadLocal的分析来看,可以得出结论:ThreadLocal不是用来解决共享对象的多线程访问问题的, 通过ThreadLocal的set()方法设置到线程的ThreadLocal.ThreadLocalMap里的是是线程自己要存储的对象,其他线程 不需要去访问,也是访问不到的。各个线程中的ThreadLocal.ThreadLocalMap以及ThreadLocal.ThreadLocal 中的值都是不同的对象。

至于为什么要使用ThreadLocal,不妨这么考虑这个问题。Java Web中,写一个Servlet:

public class Servlet extends HttpServlet 
{ 
 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } }

我在一个普通JavaBean内想拿到这个HttpServletRequest,但是无法通过参数传递的方式:

public class OperateRequest 
{ 
    public String operateRequest() 
    { 
        return null; } }

这时候怎么办?第一个解决方案,Servlet类中定义一个全局的HttpServletRequest,至于怎么定义就随便了,可以定义成静态的,也可以定义成非静态的但是对外提供setter/getter,然后operateRequest()方法每次都取这个全局的HttpServletRequest就可以了。

不否认,这是一种可行的解决方案,但是这种解决方案有一个很大的缺点:竞争。既然HttpServletRequest是全局的,那势必要引入同步机制来保证线程安全性,引入同步机制意味着牺牲响应给用户的时间—-这在注重与用户之间响应的Java Web中是难以容忍的。

所以,我们引入ThreadLocal,既然ThreadLocal.ThreadLocalMap是线程独有的,别的线程访问不了也没必要访问,那我们通过ThreadLocal把HttpServletRequest设置到线程的ThreadLocal.ThreadLocalMap里面去不就好了?这样,在一次请求中哪里需要用到HttpServletRequest,就使用ThreadLocal的get()方法就把这个HttpServletRequest给取出来了,是不是一个很好的解决方案呢?

ThreadLocal使用

忘记上面那个复杂的问题,我们来看一下ThreadLocal的简单使用,首先ThreadLocal肯定是全局共享的:

public class Tools 
{ 
    public static ThreadLocal<String> t1 = new ThreadLocal<String>(); }

写一个线程往ThreadLocal里面塞值:

public class ThreadLocalThread extends Thread 
{ 
    private static AtomicInteger ai = new AtomicInteger(); public ThreadLocalThread(String name) { super(name); } public void run() { 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) throws Exception 
    { 
        ThreadLocalThread a = new ThreadLocalThread("ThreadA"); ThreadLocalThread b = new ThreadLocalThread("ThreadB"); ThreadLocalThread c = new ThreadLocalThread("ThreadC"); a.start(); b.start(); c.start(); }

看一下运行结果:

ThreadA get value--->1 
ThreadC get value--->2 
ThreadB get value--->3 
ThreadB get value--->4 
ThreadC get value--->6 
ThreadA get value--->5 ThreadC get value--->8 ThreadA get value--->7 ThreadB get value--->9

看到每个线程的里都有自己的String,并且互不影响—-因为绝对不可能出现数字重复的情况。用一个ThreadLocal也可以多次set一个数据,set仅仅表示的是线程的ThreadLocal.ThreadLocalMap中table的某一位置的value被覆盖成你最新设置的那个数据而已,对于同一个ThreadLocal对象而言,set后,table中绝不会多出一个数据

ThreadLocal再总结

上一篇文章的最后有对ThreadLocal的工作原理进行总结,这里对ThreadLocal再次进行一个总结:

1、ThreadLocal不是集合,它不存储任何内容,真正存储数据的集合在Thread中。ThreadLocal只是一个工具,一个往各个线程的ThreadLocal.ThreadLocalMap中table的某一位置set一个值的工具而已

2、同步与ThreadLocal是解决多线程中数据访问问题的两种思路,前者是数据共享的思路后者是数据隔离的思路

3、同步是一种以时间换空间的思想,ThreadLocal是一种空间换时间的思想

4、ThreadLocal既然是与线程相关的,那么对于Java Web来讲,ThreadLocal设置的值只在一次请求中有效,是不是和request很像?因为request里面的内容也只在一次请求有效,对比一下二者的区别:

(1)ThreadLocal只能存一个值,一个Request由于是Map形式的,可以用key-value形式存多个值

(2)ThreadLocal一般用在框架,Request一般用在表示层、Action、Servlet

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/20532.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论