最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

關于TransmittableThreadLocal線程池中線程復用問題的解決方案

 更新時間:2023年11月15日 09:36:06   作者:立小研先森  
這篇文章主要介紹了關于TransmittableThreadLocal線程池中線程復用問題的解決方案,線程池復用線程,如果子線程執(zhí)行完未移除上下文,則會導致后續(xù)線程可以取到之前線程設置的屬性,需要的朋友可以參考下

TransmittableThreadLocal線程復用問題

TTL對線程或者線程池的核心通過裝飾器模式做了處理,核心如下:

  • capture:獲取父線程中的值,包括引用對象或普通對象
  • replay:回放:備份、將父線程的值設置到子線程
  • restore:將子線程執(zhí)行之前backup的值設置回子線程的ThreadLocal

一、TTL在線程池場景

線程池復用線程,如果子線程執(zhí)行完未移除上下文,則會導致后續(xù)線程可以取到之前線程設置的屬性

public class TtlErrorTest {
    private static final TransmittableThreadLocal<User> context = new TransmittableThreadLocal<>();
    
    private static final ExecutorService service = Executors.newSingleThreadExecutor();
  //TTL修飾過的線程池(1)
//  private static final Executor service = TtlExecutors.getTtlExecutor(Executors.newSingleThreadExecutor());

    public static void main(String[] args) {
      	//主線程設置上下文變量(3)
        //User user1 = new User();
        //user1.setUsername("孫少平");
        //user1.setPassword("123456");
        //context.set(user1);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                User user = new User();
                user.setUsername("田曉霞");
                context.set(user);
                System.out.println("1-" + Thread.currentThread().getName() + ":" + context.get());
                //移除上下文變量(2)
                //context.remove();
            }
        };
        Runnable runnable1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("2-" + Thread.currentThread().getName() + ":" + context.get());
            }
        };
        service.execute(runnable);
        service.execute(runnable1);
       //移除上下文(4)
        //ntext.remove();
    }
}

結果一:

1-pool-1-thread-1:田曉霞
2-pool-1-thread-1:田曉霞

結果二(將代碼中的(1)(3)打開運行):

1-pool-1-thread-1:田曉霞
2-pool-1-thread-1:孫少平

分析:上述案例定義了只有一個工作線程執(zhí)行隊列中線程的線程池,這樣做是為了立馬復現(xiàn)線程復用的效果;第一個線程中第一了上下文值引用對象,第二個線程之中沒有定義,效果是第二個線程獲取到了第一個線程之中設置的上下文變量;如果將第一個線程中(2)注釋打開,則第二個線程獲取不到第一個線程中設置的上下文變量;

如果將(1)打開會是什么效果,效果是第二個線程拿不到第一個線程中設置的上下文值,這又是為什么呢?在第一個線程中又沒有主動remove掉為何使用了TTL修飾的線程池就拿不到符合預期了呢?

如果仔細分析源碼會發(fā)現(xiàn)TTL修飾的線程使用裝飾器模式,第一步capture捕獲主線程上下文,第二部replay回放、backup備份子線程上下文、將主線程上下文值設置到子線程,第三部restore恢復階段、將backup備份恢復到子線程上下文,因為子線程上下文執(zhí)行沒有任何值,restore恢復后上下文是干凈的,上下文沒有任何值;那在第二個線程復用線程的時候是取不到指的,符合預期;

如果將(1)(3)打開運行結果也是符合預期的,這里面有個問題,無論線程一、線程二執(zhí)行完成后線程池中復用的線程都會持有一個User對象的引用,這樣GC的時候就無法回收資源,如果線程池持有的引用對象足夠多,引用對象占用的內存足夠大的時候就有可能引發(fā)OOM異常;

如果將代碼(4)打開則會移除主線程的上下文,但是子線程從父線程繼承的上下文屬性是無法移除的;

二、TTL如何保證線程池中復用的線程不持有其它線程的屬性值

針對上述線程池復用可能導致內存OOM的問題提供了兩種解決方案

方案一:通過TtlExecutors.getDefaultDisableInheritableThreadFactory()在線程池中創(chuàng)建禁止繼承父線程上下文的線程

public class TtlFactoryTest {
    private static final TransmittableThreadLocal<User> context = new TransmittableThreadLocal<>();
    static final ExecutorService service = Executors.newFixedThreadPool(2, TtlExecutors.getDefaultDisableInheritableThreadFactory());
    public static void main(String[] args) {
        User user = new User();
        user.setUsername("田曉霞");
        context.set(user);
        System.out.println("1-" + Thread.currentThread().getName() + "-" + context.get());
        service.submit(new Runnable() {
            @Override
            public void run() {
                User user1 = new User();
                user1.setUsername("田二");
                context.set(user1);
                System.out.println("2-" + Thread.currentThread().getName() + "-" + context.get());
            }
        });
        System.out.println("3-" + Thread.currentThread().getName() + "-" + context.get());
    }
}

方案二:去除掉父子線程的繼承關系,相當于TTL由InheritableThreadLocal回退到了ThreadLocal

TransmittableThreadLocal<String> t1 = new TransmittableThreadLocal<String>() {
    protected String childValue(String parentValue) {
        return initialValue();
    }
}

此方法是去除掉父子線程之間的繼承關系,會將TTL回退到ThreadLocal,對于非線程池的父子線程繼承關系是不適用的;

到此這篇關于關于TransmittableThreadLocal線程池中線程復用問題的解決方案的文章就介紹到這了,更多相關TransmittableThreadLocal線程復用問題內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • JavaWeb詳細講述Cookie和Session的概念

    JavaWeb詳細講述Cookie和Session的概念

    web開發(fā)階段我們主要是瀏覽器和服務器之間來進行交互。瀏覽器和服務器之間的交互就像人和人之間進行交流一樣,但是對于機器來說,在一次請求之間只是會攜帶著本次請求的數(shù)據(jù)的,但是可能多次請求之間是會有聯(lián)系的,所以提供了會話機制
    2022-06-06
  • Java多線程死鎖示例

    Java多線程死鎖示例

    這篇文章主要介紹了Java多線程死鎖,結合實例形式分析了Java多線程出現(xiàn)死鎖的相關原因與操作注意事項,需要的朋友可以參考下
    2018-08-08
  • Spring實例化bean的方式大全

    Spring實例化bean的方式大全

    Spring 實例化 Bean 主要有三種核心方式:構造器實例化、靜態(tài)工廠方法實例化和實例工廠方法實例化,其中構造器實例化是最常用的方式,下面小編給大家詳細說說這幾種方式,需要的朋友可以參考下
    2025-09-09
  • 基于@PathVariable注解的用法說明

    基于@PathVariable注解的用法說明

    這篇文章主要介紹了基于@PathVariable注解的用法說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java String類的常用方法匯總

    Java String類的常用方法匯總

    這篇文章主要為大家詳細匯總了Java String類的常用方法,感興趣的小伙伴們可以參考一下
    2016-07-07
  • ssm框架+PageHelper插件實現(xiàn)分頁查詢功能

    ssm框架+PageHelper插件實現(xiàn)分頁查詢功能

    今天小編教大家如何通過ssm框架+PageHelper插件實現(xiàn)分頁查詢功能,首先大家需要新建一個maven工程引入jar包,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-06-06
  • 詳解Java實踐之抽象工廠模式

    詳解Java實踐之抽象工廠模式

    抽象工廠模式用于產(chǎn)品族的構建。抽象工廠是所有形態(tài)的工廠模式中最為抽象和最具一般性的一種形態(tài)。抽象工廠是指當有多個抽象角色時使用的一種工廠模式。抽象工廠模式可以向客戶端提供一個接口,使客戶端在不必指定產(chǎn)品的具體情況下,創(chuàng)建多個產(chǎn)品族中的產(chǎn)品對象
    2021-06-06
  • Java使用jacob將微軟office中word、excel、ppt轉成pdf

    Java使用jacob將微軟office中word、excel、ppt轉成pdf

    這篇文章主要為大家詳細介紹了Java使用jacob將微軟office中word、excel、ppt轉成pdf,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • Java 8中字符串拼接新姿勢StringJoiner詳解

    Java 8中字符串拼接新姿勢StringJoiner詳解

    在本篇文章里小編給大家整理了關于Java 8中字符串拼接新姿勢StringJoiner的詳解內容,需要的朋友們參考下。
    2019-09-09
  • Java Spring三級緩存

    Java Spring三級緩存

    三級緩存就是在Bean生成流程中保存Bean對象三種形態(tài)的三個Map集合,這個三級緩存就是為了解決循環(huán)依賴,本文給大家介紹Java Spring三級緩存,感興趣的朋友一起看看吧
    2025-06-06

最新評論

神木县| 高邑县| 固始县| 佛学| 长泰县| 房山区| 祥云县| 双峰县| 忻州市| 永福县| 东乡县| 莫力| 安福县| 定边县| 溧阳市| 京山县| 卓资县| 上蔡县| 晋州市| 休宁县| 丰顺县| 柳河县| 盐边县| 昂仁县| 馆陶县| 高邮市| 新和县| 阜阳市| 尤溪县| 天长市| 通榆县| 宝山区| 鄂尔多斯市| 重庆市| 横山县| 贡嘎县| 榆林市| 海口市| 惠水县| 西平县| 龙游县|