• java多线程18: 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给取出来了,是不是一个很好的解决方案呢?


    在这里我原先也写了篇笔记 ,可以先看看java 中的 ThreadLocal

     

    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设置值的话,是会返回null的



    ThreadLocal.get 返回null解决




    上面的对threadlocal 进行了初始化,从而没有进入 判断为null的if分支




    InheritableThreadLocal的使用,值继承,继承父线程InheritableThreadLocal的值






    从上面可以看得出来,使用InheritableThreadLocal子线程会自动继承父线程的InheritableThreadLocal值



    InheritableThreadLocal值继承再修改




    跟上面一样,继承childValue可以在子线程使用InheritableThreadLocal自动调用这个方法初始化子线程的值,记住只是初始化,也就是只执行一次,当父线程再次修改InheritableThreadLocal的值时,子线程取的就是父线程修改后的值了







  • 相关阅读:
    5359. 最大的团队表现值
    Trie树模板
    [NOIP 2009] 细胞分裂(选做)
    【SpringCloud】07.应用间的通信
    【SpringCloud】06.Eureka 总结
    【SpringCloud】05.Eureka的高可用
    【SpringCloud】04.SpringCloud Eureka Server与Client的创建
    【SpringCloud】03.微服务的设计原则
    【SpringCloud】02.微服务与SpringCloud
    【SpringCloud】01.常见软件架构的区别
  • 原文地址:https://www.cnblogs.com/signheart/p/fa258acd0eb38a06b5075ea28bab11b0.html
Copyright © 2020-2023  润新知