• 多线程(八)~ThreadLocal、InheritableThreadLocal的使用


        通过前面的学习,我们了解了在多线程+成员变量等情况下会出现线程安全的问题。那么解决线程安全问题除了使用synchronize关键字之外,还有另一种常用的解决思路,那就是使用ThreadLocal类,下面我们会对这个类做一下简介并指出两者的差异。

     
        ThreadLocal:通过字面翻译过来意思是“线程本地”,代表线程自己的本地变量。在多线程环境下,所有线程会共享类中的成员变量,那么这种情况下有可能会引发线程安全的问题。如果线程有自己的本地变量是不是就不会冲突了,ThreadLocal的原理就是这样,为线程创建自己的本地变量,多个线程间不共享。
     
        线程本地变量最初始是空值null,最最常用的方法就是get()、set(Object value),其实这些值是维护在一个ThreadLocalMap中的。
      简单的get()、set()的demo:
    1. package com.multiThread.test.mythreadlocal;
    2. publicclassSampleTest{
    3. //线程本地变量
    4. publicstaticThreadLocal tl =newThreadLocal();
    5. publicstaticvoid main(String[] args){
    6. if(tl.get()==null){
    7. System.out.println("线程初始变量是空值");
    8. tl.set("我的值");
    9. }
    10. System.out.println(tl.get());
    11. System.out.println(tl.get());
    12. }
    13. }
     
    线程变量的隔离性(非共享)
    线程本地变量工具类:
    1. package com.multiThread.util;
    2. publicclassThreadLocalUtil{
    3. publicstaticfinalThreadLocal<String> tl =newThreadLocal<String>();
    4. }
    线程类:
    1. package com.multiThread.thread;
    2. import com.multiThread.util.ThreadLocalUtil;
    3. publicclassMyThreadLocalAimplementsRunnable{
    4. @Override
    5. publicvoid run(){
    6. for(int i =0;i<100;i++){
    7. ThreadLocalUtil.tl.set("ThreadA:"+(i +1));
    8. System.out.println("ThreadA:"+ThreadLocalUtil.tl.get());
    9. try{
    10. Thread.sleep(20);
    11. }catch(InterruptedException e){
    12. e.printStackTrace();
    13. }
    14. }
    15. }
    16. }
    1. package com.multiThread.thread;
    2. import com.multiThread.util.ThreadLocalUtil;
    3. publicclassMyThreadLocalBimplementsRunnable{
    4. @Override
    5. publicvoid run(){
    6. for(int i =0;i<100;i++){
    7. ThreadLocalUtil.tl.set("ThreadB:"+(i +1));
    8. System.out.println("ThreadB:"+ThreadLocalUtil.tl.get());
    9. try{
    10. Thread.sleep(20);
    11. }catch(InterruptedException e){
    12. e.printStackTrace();
    13. }
    14. }
    15. }
    16. }
    测试类:
    1. package com.multiThread.test.mythreadlocal;
    2. import com.multiThread.thread.MyThreadLocalA;
    3. import com.multiThread.thread.MyThreadLocalB;
    4. publicclassMyThreadRun{
    5. publicstaticvoid main(String[] args){
    6. MyThreadLocalA myThreadLocalA =newMyThreadLocalA();
    7. MyThreadLocalB myThreadLocalB =newMyThreadLocalB();
    8. Thread t1 =newThread(myThreadLocalA);
    9. Thread t2 =newThread(myThreadLocalB);
    10. t1.start();
    11. t2.start();
    12. }
    13. }
    测试结果:
    1. .
    2. .
    3. .
    4. ThreadB:ThreadB:95
    5. ThreadA:ThreadA:95
    6. ThreadB:ThreadB:96
    7. ThreadA:ThreadA:96
    8. ThreadB:ThreadB:97
    9. ThreadA:ThreadA:97
    10. ThreadA:ThreadA:98
    11. ThreadB:ThreadB:98
    12. ThreadB:ThreadB:99
    13. ThreadA:ThreadA:99
    14. ThreadB:ThreadB:100
    15. ThreadA:ThreadA:100
    通过结果可以看出线程A和线程B之间的变量并非共享的,线程本地变量具有隔离性,只是自己用的。
     
    为线程本地变量初始化值:
        继承自ThreadLocal类,并实现initialValue(),设置返回值即可。
    1. publicstaticfinalThreadLocal myLocal =newThreadLocal(){
    2. protectedObject initialValue(){
    3. return250;
    4. };
    5. };
    1. System.out.println("默认值为:" + TicketThread.myLocal.get());
    1. 默认值为:250
     
    InheritableThreadLocal可以使子线程能从父线程中获取本地变量的值,例如:
    子线程类:
    1. package com.wang.threadlocal;
    2. publicclassPersonimplementsRunnable{
    3. @Override
    4. publicvoid run(){
    5. System.out.println("从父线程中获取线程变量:"+MyInheritableThradLocal.threadLocal.get());
    6. }
    7. }
     
    测试类:
    1. package com.wang.threadlocal;
    2. publicclassInheritableTest{
    3. publicstaticvoid main(String[] args){
    4. MyInheritableThradLocal.threadLocal.set("who let the dogs out?");
    5. System.out.println("Main线程中的值为:"+MyInheritableThradLocal.threadLocal.get());
    6. Person person =newPerson();
    7. Thread t1 =newThread(person);
    8. t1.start();
    9. }
    10. }
    从例子中可以看出,在main线程中设置的线程本地变量,在子线程中也能拿到。
    注意:若子线程获取值的同时,父线程对线程本地变量值做了修改,则子线程取到的值还是原值。
     
     
     
        





  • 相关阅读:
    利用Fiddler模拟通过Dynamics 365的OAuth 2 Client Credentials认证后调用Web API
    Dynamics CRM中的操作(action)是否是一个事务(transaction)?
    Dynamics CRM 2015/2016新特性之三十二:新增乐观并发处理
    Dynamics CRM 2015/2016新特性之三十三:有了ExecuteTransactionRequest,再也不用担心部分成功部分失败了
    提权案例(一)渗透某asp.net网站通过sql server数据库public 提权 思路分享
    windows 抓hash获取管理员密码
    第三方应用 flashfxp,filezilla提权
    第三方软件 G6ftp提权
    第三方软件 vnc提权
    第三方软件 radmin提权
  • 原文地址:https://www.cnblogs.com/douJiangYouTiao888/p/6473818.html
Copyright © 2020-2023  润新知