您好!欢迎来到爱源码

爱源码

热门搜索: 抖音快手短视频下载   

了解简单的线程本地 <导航网站源码>

  • 时间:2022-09-01 01:29 编辑: 来源: 阅读:308
  • 扫一扫,手机访问
摘要:了解简单的线程本地 <导航网站源码>
ThreadLocal类ThreadLocal的细节,表面上是英文的线程局部变量的意思,可能更好理解。它是每个线程独有的变量,不与其他线程共享。 常用的只有这些,两个内部类和四个方法。 get()方法用于获取当前线程中ThreadLocal保存的变量的副本。 Set()用于设置当前线程中变量的副本。 Remove()用于删除当前线程中变量的副本。 InitialValue()是一个受保护的方法,一般用于使用时重写。这是一种延期装载方法。 当ThreadLocal没有被当前线程赋值或者当前线程只是调用remove方法时,它调用get方法并返回该方法的值。 比如定义两个任务不同的线程,在各自的局部变量中存储值,见证两个线程局部变量的内容互不干扰。 class my thread local {//通过匿名内部类重写initialValue方法。私有静态最终线程本地< Object >threadLocal = new ThreadLocal & ltObject & gt(){/* * *调用get方法当ThreadLocal不是当前线程分配的或者就在当前线程调用remove方法之后,返回此方法的值*/@ override protected object initialValue(){ system . out . println("调用get方法时,当前线程共享变量没有设置,所以调用initial value获取默认值!");返回null} };//操纵int类型的任务线程,公共静态类MyIntegerTask实现Runnable { Private String NameMyIntegerTask(字符串名称){ this.name = name} public void run(){ for(int I = 0;我& lt5;++){//thread local . get方法获取线程变量if(null = = mythread local . thread local . get()){//thread local . et方法设置线程变量mythread local . thread local . set(0);system . out . println(" thread "+name+":0 ");} else { int num =(Integer)mythreadlocal . thread local . get();mythreadlocal . thread local . set(num+1);system . out . println(" thread "+name+":"+mythread local . thread local . get());if(I = = 3){ mythreadlocal . thread local . remove();} }试试{ thread . sleep(1000);} catch(interrupted exception e){ e . printstacktrace();} } } }//操纵string类型的任务线程,公共静态类mystring任务实现runnable { privatestringnameMyStringTask(字符串名称){ this.name = name} public void run(){ for(int I = 0;我& lt5;i++){ if(null = = mythreadlocal . thread local . get()){ mythreadlocal . thread local . set(" a ");system . out . println(" thread "+name+":a ");} else { String str =(String)mythreadlocal . thread local . get();mythreadlocal . thread local . set(str+" a ");system . out . println(" thread "+name+":"+mythread local . thread local . get());}试试{ thread . sleep(800);} catch(interrupted exception e){ e . printstacktrace();} } } } public static void main(String[]args){ new Thread(new myinteger task(" integer task 1 "))。start();新线程(新MyStringTask("StringTask1 "))。start();}}运行结果:调用get方法时,没有设置当前线程共享变量。调用initialValue获取默认值!thread IntegerTask1: 0调用get方法时,不设置当前线程共享变量。调用initialValue获取默认值!Thread string task 1:a Thread string task 1:aa Thread integer task 1:1 Thread string task 1:2 Thread string task 1:AAAA Thread integer task 1:3 Thread string task 1:AAAA调用get方法时,不设置当前线程共享变量。调用initialValue获取默认值!Thread IntegerTask1: 0get方法分析涉及的源代码:get();方法:让ThreadLocal对象调用publictget(){ threadt = thread . current thread();ThreadLocalMap map = get map(t);如果(图!= null) { ThreadLocalMap。entry e = map . get entry(this);如果(e!= null){ @ suppress warnings(" unchecked ")T result =(T)e . value;返回结果;} }返回setinitial value();} get map();方法:该方法返回当前线程T中的一个成员变量Threadlocales,是thread类中的一个内部类thread local . thread local map thread locales = null;ThreadLocalMap get map(Thread t){ return t . Thread locals;}看一下ThreadLocalMap的实现:可以看到ThreadLocalMap的条目继承了WeakReference类,使用ThreadLocal作为键值。 静态类ThreadLocalMap { static class Entry扩展WeakReference & ltThreadLocal & lt?& gt& gt{ /**与此ThreadLocal关联的值。*/对象值;entry(thread local & lt;?& gtk,Object v){ super(k);值= v;} } } getEntry();方法private entry getentry(thread local 然后得到以下内容 测试完上面的例子,看了get方法的实现,你应该明白ThreadLocal的原理了,大致如下(就是这样):首先,有一个ThreadLocal类型的成员变量threadLocals。ThreadLocalMap,这个threadLocals用于存储实际的变量。键值是当前的ThreadLocal变量,值是一个变量(例如,上面定义的字符串变量或整数变量) 开始时,在Thread中,threadLocals为空。当通过ThreadLocal变量调用get()方法或set()方法时,Thread类中的threadLocals将被初始化,当前ThreadLocal变量将作为键值,ThreadLocal要保存的变量将作为值,存储在threadLocals中。 如果要使用复制变量,可以通过get方法在threadLocals中找到。 这种存储结构的优点是,当一个线程死亡时,线程共享变量ThreadLocalMap被销毁。 ThreadLocalMap & ltThreadLocal,Object & gt一般来说,与使用map相比,ThreadLocal的数量对于键值的数量来说非常小 ThreadLocal应用场景最常见的ThreadLocal应用场景用于处理数据库连接、会话管理等。 比如代码来自:https://www.iteye.com/topic/103804private静态最终线程本地线程session = new thread local();公共静态会话getSession()抛出infrastructure exception { Session s =(Session)thread Session . get();请尝试{ if(s = = null){ s = getsession factory()。openSession();threadSession.set} } catch(hibernate exception ex){ throw new infra structure exception(ex);} return s;}关于ThreadLocal导致的内存泄漏,以及解决方案,每个线程中都有一个map,map的类型是ThreadLocal。ThreadLocalMap Map中的键是threadlocal实例。 此映射确实使用了弱引用,但弱引用仅用于键。 每个键都有一个对threadlocal的弱引用。当threadlocal实例设置为null时,没有对threadlocal实例的强引用,因此threadlocal将被gc回收。 但是value不能回收,因为有一个从currentThread连接的强引用。 只有currentThread结束后,栈中才会不存在CurrentThread,强引用会被打破,当前线程、Map、value都会被GC回收。 所以得出一个结论,只要这个线程对象被gc回收,就不会有内存泄漏,但是在threadLocal设置为null,线程结束的这段时间内不会被回收,我们认为的内存泄漏就会发生。 其实这是对概念的不一致理解,没什么好争论的。 最糟糕的是线程对象没有被回收,导致真正的内存泄漏。 比如使用线程池时,线程端不会被破坏,会被再次使用。 也就是说,可能会发生内存泄漏。 为了最小化内存泄漏的可能性和影响,Java在获取和设置ThreadLocal时,会清理线程映射中所有带有空键的值。 所以最怕的情况是当threadLocal对象设置为null时,开始出现“内存泄漏”,然后使用线程池。当线程结束后,线程没有被销毁就被放回线程池,并且线程一直没有被使用,或者线程被分配后没有再次调用get和set方法,那么这段时间就会发生真正的内存泄漏。 一般有两种方法:使用线程共享变量后,显示并调用ThreadLocalMap.remove方法清理线程共享变量。JDK建议将ThreadLocal定义为私有静态,这样就不存在ThreadLocal的弱引用问题。


  • 全部评论(0)
资讯详情页最新发布上方横幅
最新发布的资讯信息
【域名/主机/服务器|】qq邮箱提醒在哪里打开(2024-06-04 18:58)
【技术支持|常见问题】1556原创ng8文章搜索页面不齐(2024-05-01 14:43)
【技术支持|常见问题】1502企业站群-多域名跳转-多模板切换(2024-04-09 12:19)
【技术支持|常见问题】1126完美滑屏版视频只能显示10个(2024-03-29 13:37)
【技术支持|常见问题】响应式自适应代码(2024-03-24 14:23)
【技术支持|常见问题】1126完美滑屏版百度未授权使用地图api怎么办(2024-03-15 07:21)
【技术支持|常见问题】如何集成阿里通信短信接口(2024-02-19 21:48)
【技术支持|常见问题】算命网微信支付宝产品名称年份在哪修改?风水姻缘合婚配对_公司起名占卜八字算命算财运查吉凶源码(2024-01-07 12:27)
【域名/主机/服务器|】帝国CMS安装(2023-08-20 11:31)
【技术支持|常见问题】通过HTTPs测试Mozilla DNS {免费源码}(2022-11-04 10:37)

联系我们
Q Q:375457086
Q Q:526665408
电话:0755-84666665
微信:15999668636
联系客服
企业客服1 企业客服2 联系客服
86-755-84666665
手机版
手机版
扫一扫进手机版
返回顶部