<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          ThreadLocal概念以及使用場景

          共 699字,需瀏覽 2分鐘

           ·

          2021-10-22 12:31

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”

          優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

          根據(jù)自身的知識深度,這里只限于自己使用和學(xué)習(xí)的知識點(diǎn)整理,原理的解釋還需要再沉淀。

          該文章從項(xiàng)目開發(fā)中舉例,希望能幫助到各位,不了解ThreadLocal的朋友,可能會問,這是個(gè)是什么,這有什么用,這能用在哪些地方,接下來我一一解釋,如果有地方解釋不好,希望多多包含。

          概念:

          這是個(gè)是什么:

          ThreadLocal是一個(gè)類,是一個(gè)本地線程,提供了一種線程安全的方式,用來避免共享數(shù)據(jù)(線程變量隔離)。

          翻看源碼可以看到注釋(已翻譯):

          此類提供線程局部變量。這些變量不同于它們的普通對應(yīng)變量,因?yàn)槊總€(gè)訪問一個(gè)(通過其get或set方法)的線程都有自己的、獨(dú)立初始化的變量副本。ThreadLocal實(shí)例通常是希望將狀態(tài)與線程相關(guān)聯(lián)的類中的私有靜態(tài)字段(例如,用戶 ID 或事務(wù) ID)

          這有什么用:

          按照《Java核心卷一》來說,有時(shí)候可能要避免共享變量,使用ThreadLocal輔助類為各個(gè)線程提供各自的實(shí)例;

          就是說,每個(gè)線程都有一個(gè)伴生的空間(ThreadLocal),存儲私有的數(shù)據(jù)。

          只要線程存在,就能拿到對應(yīng)的ThreadLocal中存儲的值。

          創(chuàng)建以及提供的方法

          創(chuàng)建一個(gè)線程局部變量,其初始值通過調(diào)用給定的提供者(Supplier)生成;

          public?static??ThreadLocal?withInitial(Supplier?supplier)?{
          ????????return?new?SuppliedThreadLocal<>(supplier);
          ????}

          使用的方法也比較少:

          這里就列出用的比較多的方法:

          返回此線程局部變量的當(dāng)前線程副本中的值。如果該變量對于當(dāng)前線程沒有值,則首先將其初始化為調(diào)用initialValue方法返回的值:

          T?get()

          將此線程局部變量的當(dāng)前線程副本設(shè)置為指定值;

          value -- 要存儲在此線程本地的當(dāng)前線程副本中的值

          void?set(T?value)

          刪除此線程局部變量的當(dāng)前線程值(刪除這里有些講究,暫且不表,留在后面)

          void?remove()

          項(xiàng)目實(shí)例:

          ThreadLocal使用的場景主要是:(引用)

          每個(gè)線程需要自己獨(dú)立的實(shí)例且該實(shí)例需要在多個(gè)方法中使用

          以下是個(gè)人使用的場景:

          自己為什么會使用它,我是想在項(xiàng)目中直接獲取當(dāng)前用戶的信息,這個(gè)功能就使用了ThreadLocal;

          首先創(chuàng)建一個(gè)ThreadLocal類:

          import?com.xbhog.springbootvueblog.pojo.SysUser;

          public?class?UserThreadLocal?{
          ????private??UserThreadLocal(){}

          ????private?static?final?ThreadLocal?LOCAL?=?new?ThreadLocal<>();

          ????public?static?void?put(SysUser?sysUser){
          ????????LOCAL.set(sysUser);
          ????}
          ????public?static?SysUser?get(){
          ????????return?LOCAL.get();
          ????}

          ????public?static?void?remove(){
          ????????LOCAL.remove();
          ????}
          }


          其中包含了數(shù)據(jù)的添加刪除和獲取,因?yàn)槲覀冃枰氖怯脩粜畔ⅲ敲淳桶裊ser類傳入泛型中;

          操作的對象有了,接下來就是使用:

          在該項(xiàng)目中個(gè)人使用的地方在登錄攔截器中,當(dāng)對登錄的信息檢查成功后,那么將當(dāng)前的用戶對象加入到ThreadLocal中,

          //登錄驗(yàn)證成功,放行
          System.out.println("走到UserThreadLocal--------");
          UserThreadLocal.put(sysUser);

          在controller中使用的時(shí)候,直接調(diào)用ThreadLocal中的get方法,就可以獲得當(dāng)前用戶的信息:

          //獲取當(dāng)前在線用戶信息
          SysUser?sysUser?=?UserThreadLocal.get();

          資源調(diào)用完成后需要在攔截器中刪除ThreadLocal資源:

          @Override
          public?void?afterCompletion(HttpServletRequest?request,?HttpServletResponse?response,?Object?handler,?Exception?ex)?throws?Exception?{
          ????//使用完的用戶信息需要?jiǎng)h除,防止內(nèi)存泄露
          ????UserThreadLocal.remove();
          }


          afterCompletion作用:

          實(shí)現(xiàn)最終的完成后進(jìn)行處理,該方法在執(zhí)行完控制器之后執(zhí)行,由于是在Controller方法執(zhí)行完畢后執(zhí)行該方法,所以該方法適合進(jìn)行一些資源清理,記錄日志信息等處理操作

          什么意思呢:

          程序首先執(zhí)行攔截器類中的preHandle()方法,如果該方法返回值是true,則程序會繼續(xù)向下執(zhí)行處理器中的方法,否則不再向下執(zhí)行;在業(yè)務(wù)控制器類Controller(這里就可以用ThreadLocal 獲取用戶信息)處理完請求后,會執(zhí)行postHandle()方法,

          而后會通過DispatcherServlet向客戶端返回響應(yīng);在DispatcherServlet處理完請求后,才會執(zhí)行afterCompletion()方法(這里刪除這次請求的ThreadLocal 中的user信息);

          ThreadLocal的內(nèi)存泄露問題:

          如果我們在使用完該線程后不進(jìn)行ThreadLocal 中的變量進(jìn)行刪除,那么就會造成內(nèi)存泄漏的問題,那么該問題是怎么出現(xiàn)的?

          首先先看一下ThreadLocal 內(nèi)部結(jié)構(gòu):

          首先對于對象在棧中保存的是對象的引用,對象的存儲在堆中,要先明確概念。棧中的格式也符合我們上述我們畫的圖1,其中Heap中的map是ThreadLocal map,里面包含key和value,其中value就是我們需要保存的變量數(shù)據(jù),key則是ThreadLocal實(shí)例;

          即:每一個(gè)Thread維護(hù)一個(gè)ThreadLocalMap, key為使用弱引用的ThreadLocal實(shí)例,value為線程變量的副本。

          還需要注意的是上述圖片的連接有實(shí)線和虛線,實(shí)線代表強(qiáng)引用,虛線表示弱引用;

          掃盲強(qiáng)引用、軟引用、弱引用、虛引用:??

          1. 強(qiáng)引用,我們使用的大部分引用都是強(qiáng)引用,特點(diǎn)就是當(dāng)內(nèi)存不足時(shí),垃圾回收器寧愿自己拋出OOM,也不會回收強(qiáng)引用來解決內(nèi)存不足的問題

          2. 軟引用,就是生殺大權(quán)都在垃圾回收器中,我內(nèi)存夠的話,你可以活著,如果不夠的話,我就回收你,給我騰地方;

          3. 弱引用,只要垃圾回收器掃到,不管空間夠不夠,都給我回收了;

          4. 虛引用,形同虛設(shè)的東西,在任何情況下都可能被回收

          這里只給出了概念,如果感興趣可以自行了解作用環(huán)境。

          那么知道強(qiáng)引用、弱引用后我們再來看圖,因?yàn)門hreadLocal與線程屬于同一個(gè)生命周期,當(dāng)在某一個(gè)階段進(jìn)行了一次GC,那么當(dāng)前線程還在,但是ThreadLocal實(shí)例被回收了,也就是key沒了,

          我們都知道,map中的value需要key找到,key沒了,那么value就會永遠(yuǎn)的留在內(nèi)存中,直到內(nèi)存滿了,導(dǎo)致OOM,所以我們就需要使用完以后進(jìn)行手動(dòng)刪除,這樣能保證不會出現(xiàn)因?yàn)镚C的原因造成的OOM問題;


          ? 作者?|??xbhog

          來源 |??cnblogs.com/xbhog/p/15411167.html


          加鋒哥微信:?java1239??
          圍觀鋒哥朋友圈,每天推送Java干貨!

          瀏覽 65
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    91综合网 | 青草视频网站 | 国产精品操 | 免费靠逼视频 | 色色免费小电影 |