亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

關(guān)于TransmittableThreadLocal線程池中線程復(fù)用問題的解決方案

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

TransmittableThreadLocal線程復(fù)用問題

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

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

一、TTL在線程池場景

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

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) {
      	//主線程設(shè)置上下文變量(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();
    }
}

結(jié)果一:

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

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

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

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

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

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

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

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

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

針對上述線程池復(fù)用可能導(dǎo)致內(nèi)存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());
    }
}

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

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

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

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

相關(guān)文章

  • Spring Boot利用Lombok減少Java中樣板代碼的方法示例

    Spring Boot利用Lombok減少Java中樣板代碼的方法示例

    spring Boot是非常高效的開發(fā)框架,lombok是一套代碼模板解決方案,將極大提升開發(fā)的效率,下面這篇文章主要給大家介紹了關(guān)于Spring Boot利用Lombok減少Java中樣板代碼的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-09-09
  • Springboot詳解整合SpringSecurity實現(xiàn)全過程

    Springboot詳解整合SpringSecurity實現(xiàn)全過程

    Spring Security基于Spring開發(fā),項目中如果使用Springboot作為基礎(chǔ),配合Spring Security做權(quán)限更加方便,而Shiro需要和Spring進行整合開發(fā)。因此作為spring全家桶中的Spring Security在java領(lǐng)域很常用
    2022-07-07
  • SpringBoot整合Ip2region獲取IP地址和定位的詳細過程

    SpringBoot整合Ip2region獲取IP地址和定位的詳細過程

    ip2region v2.0 - 是一個離線IP地址定位庫和IP定位數(shù)據(jù)管理框架,10微秒級別的查詢效率,提供了眾多主流編程語言的 xdb 數(shù)據(jù)生成和查詢客戶端實現(xiàn) ,這篇文章主要介紹了SpringBoot整合Ip2region獲取IP地址和定位,需要的朋友可以參考下
    2023-06-06
  • Java的靜態(tài)方法Arrays.asList()使用指南

    Java的靜態(tài)方法Arrays.asList()使用指南

    Arrays.asList() 是一個 Java 的靜態(tài)方法,它可以把一個數(shù)組或者多個參數(shù)轉(zhuǎn)換成一個 List 集合,這個方法可以作為數(shù)組和集合之間的橋梁,方便我們使用集合的一些方法和特性,本文將介紹 Arrays.asList() 的語法、應(yīng)用場景、坑點和總結(jié)
    2023-09-09
  • Java每7天日志自動清理的項目實踐

    Java每7天日志自動清理的項目實踐

    在實際項目中由于服務(wù)器內(nèi)存有限,人工清理常會忘記,本文主要介紹了Java每7天日志自動清理的項目實踐,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • java 文件目錄讀寫刪除操作詳細實現(xiàn)代碼

    java 文件目錄讀寫刪除操作詳細實現(xiàn)代碼

    這篇文章主要介紹了java 文件讀寫刪操作詳細實現(xiàn)代碼,需要的朋友可以參考下
    2017-09-09
  • java中set集合的常用方法詳解

    java中set集合的常用方法詳解

    本篇文章給大家?guī)淼膬?nèi)容是關(guān)于java中set集合的常用方法詳解,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。下面我們就來學習一下吧
    2021-11-11
  • 詳解java倒計時三種簡單實現(xiàn)方式

    詳解java倒計時三種簡單實現(xiàn)方式

    這篇文章主要介紹了詳解java倒計時三種簡單實現(xiàn)方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • Spring的自動裝配Bean的三種方式

    Spring的自動裝配Bean的三種方式

    本篇文章主要介紹了 Spring的自動裝配Bean的三種方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02
  • Java?Optional用法面試題精講

    Java?Optional用法面試題精講

    這篇文章主要為大家介紹了Java?Optional用法面試題精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09

最新評論