1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        ThreadLocal概念以及使用場(chǎng)景

        共 699字,需瀏覽 2分鐘

         ·

        2021-10-22 12:31

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

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

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

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

        概念:

        這是個(gè)是什么:

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

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

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

        這有什么用:

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

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

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

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

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

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

        使用的方法也比較少:

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

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

        T?get()

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

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

        void?set(T?value)

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

        void?remove()

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

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

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

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

        自己為什么會(huì)使用它,我是想在項(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)槲覀冃枰氖怯脩粜畔?,那么就把User類傳入泛型中;

        操作的對(duì)象有了,接下來(lái)就是使用:

        在該項(xiàng)目中個(gè)人使用的地方在登錄攔截器中,當(dāng)對(duì)登錄的信息檢查成功后,那么將當(dāng)前的用戶對(duì)象加入到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,則程序會(huì)繼續(xù)向下執(zhí)行處理器中的方法,否則不再向下執(zhí)行;在業(yè)務(wù)控制器類Controller(這里就可以用ThreadLocal 獲取用戶信息)處理完請(qǐng)求后,會(huì)執(zhí)行postHandle()方法,

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

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

        如果我們?cè)谑褂猛暝摼€程后不進(jìn)行ThreadLocal 中的變量進(jìn)行刪除,那么就會(huì)造成內(nèi)存泄漏的問題,那么該問題是怎么出現(xiàn)的?

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

        首先對(duì)于對(duì)象在棧中保存的是對(duì)象的引用,對(duì)象的存儲(chǔ)在堆中,要先明確概念。棧中的格式也符合我們上述我們畫的圖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,也不會(huì)回收強(qiáng)引用來(lái)解決內(nèi)存不足的問題

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

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

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

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

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

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


        ? 作者?|??xbhog

        來(lái)源 |??cnblogs.com/xbhog/p/15411167.html


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

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

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

          <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            亚洲无码av在线观看 | 亚洲色图欧美色图自慰直播 | 丁香婷婷五月综合小说99在线 | 娇欲1v1高h高辣1v1林宴 | 婷婷五月天激情网 | 日本人妖中文字幕久久 | 成人爱操B | 肥逼网站| 久久无精品国产99久久果冻传媒 | 日本黄色录像带 |