• 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

  • 相关阅读:
    浅析String.intern()方法
    com.alibaba.druid.pool.DruidPooledConnection cannot be cast to oracle.jdbc.OracleConnection 异常解决办法
    ChannelEventRunnable handle RECEIVED operation error, channel is NettyChannel解决方法
    jsch channel is not opened原因及解决
    学习地址(oraclemysqllinux)
    python中数据分析常用函数整理
    Python之使用Pandas库实现MySQL数据库的读写
    Python数据分析
    如何用sql查询出连续三个月金额大于50的记录
    【Python项目实战】Pandas:让你像写SQL一样做数据分析(一)
  • 原文地址:https://www.cnblogs.com/xrq730/p/4854820.html
Copyright © 2020-2023  润新知