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

Java中的ThreadLocal詳解

 更新時間:2023年09月26日 10:06:35   作者:菜鳥小窩  
這篇文章主要介紹了Java中的ThreadLocal詳解,ThreadLocal?是一個線程局部變量,其實的功用非常簡單,就是為每一個使用該變量的線程都提供一個變量值的副本,是Java中一種較為特殊的線程綁定機制,需要的朋友可以參考下

一、ThreadLocal

1、說明

ThreadLocal 是一個線程局部變量。其實的功用非常簡單,就是為每一個使用該變量的線程都提供一個變量值的副本,是Java中一種較為特殊的線程綁定機制,是每一個線程都可以獨立地改變自己的副本,而不會和其它線程的副本沖突。

2、使用方法

ThreadLocal<String> nameThreadLocal = new ThreadLocal<>();
nameThreadLocal.set(name);
nameThreadLocal.get();

3、Request 使用案例

  1. 在controller中注入的request是jdk動態(tài)代理對象,ObjectFactoryDelegatingInvocationHandler的實例.當我們調用成員域request的方法的時候其實是調用了objectFactory的getObject()對象的相關方法.這里的objectFactory是RequestObjectFactory
  2. RequestObjectFactory的getObject其實是從RequestContextHolder的threadlocal中去取值的
  3. 請求剛進入springmvc的dispatcherServlet的時候會把request相關對象設置到RequestContextHolder的threadlocal中去

二、InheritableThreadLocal

1、說明

ThreadLocal設計之初就是為了綁定當前線程,如果希望當前線程的ThreadLocal能夠被子線程使用,實現(xiàn)方式就會相當困難(需要用戶自己在代碼中傳遞)。在此背景下,InheritableThreadLocal應運而生。

2、原理

創(chuàng)建新的線程時,會調用以下的構造方法。

    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

我們沿著構造方法中的init方法,可以找到這樣一段代碼。就是在這里創(chuàng)建的 inheritableThreadLocals 。

        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);

繼續(xù)查看 createInheritedMap 方法,里面新建了一個 ThreadLocalMap 對象,其構造方法如下。

分析代碼我們可知,在創(chuàng)建子線程時,會將父線程的 inheritableThreadLocals 復制到子線程的 inheritableThreadLocals 對象。

        private ThreadLocalMap(ThreadLocalMap parentMap) {
            Entry[] parentTable = parentMap.table;
            int len = parentTable.length;
            setThreshold(len);
            table = new Entry[len];
            for (int j = 0; j < len; j++) {
                Entry e = parentTable[j];
                if (e != null) {
                    @SuppressWarnings("unchecked")
                    ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
                    if (key != null) {
                        Object value = key.childValue(e.value);
                        Entry c = new Entry(key, value);
                        int h = key.threadLocalHashCode & (len - 1);
                        while (table[h] != null)
                            h = nextIndex(h, len);
                        table[h] = c;
                        size++;
                    }
                }
            }
        }

三、TransmittableThreadLocal

1、概述

使用線程池時,線程會被復用,因此線程池中的線程,執(zhí)行任務時如果要獲取 提交線程(即 提交任務到線程池 的線程) 保存的對象,則可以使用 TransmittableThreadLocal 。

2、使用方法

TransmittableThreadLocal<String> ttl = new TransmittableThreadLocal<>();
ThreadPoolExecutor executor = new ThreadPoolExecutor(ThreadSize, ThreadSize, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10));
// 設置變量,并將任務提交到線程池
ttl.set("ThreadA-TTL");
Runnable task = new Runnable() {
    @Override
    public void run() {
        System.out.println(ttl.get());
    }
};
// 生成修飾后的對象ttlRunnable。
task = TtlRunnable.get(task);
executor.submit(task);

3、案例(業(yè)務侵入式)

(1)代碼

package com.scy.example.controller;
import com.alibaba.ttl.TransmittableThreadLocal;
import com.alibaba.ttl.TtlRunnable;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Test02 {
    static ThreadPoolExecutor executor = null;
    static TransmittableThreadLocal<String> ttl = new TransmittableThreadLocal<>();
    public static void main(String[] args) {
        try {
            // 在A線程中創(chuàng)建線程池,并且啟動線程池中的線程
            Thread threadA = new Thread(() -> {
                int ThreadSize = 1;
                executor = new ThreadPoolExecutor(ThreadSize, ThreadSize, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10));
                ttl.set("ThreadA-TTL");
                // 啟動線程池中的線程
                for (int i = 0; i < ThreadSize; i++) {
                    executor.submit(() -> {
                        System.out.println("初始化線程完畢!");
                    });
                }
            });
            threadA.start();
            // 等待線程池中的線程啟動完畢
            Thread.sleep(100);
            // 在B線程中,向線程池提交任務
            Thread threadB = new Thread(() -> {
                ttl.set("ThreadB-TTL");
                Runnable task = new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(ttl.get());
                    }
                };
                // 額外的處理,生成修飾了的對象ttlRunnable
                task = TtlRunnable.get(task);
                executor.submit(task);
            });
            threadB.start();
            Thread.sleep(100);
            executor.shutdown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

(2)結果

初始化線程完畢!
ThreadB-TTL

(3)說明

使用 TransmittableThreadLocal 存儲對象時;

如果任務沒有使用 TtlRunnable 修飾,則 TransmittableThreadLocal 相當于 InheritableThreadLocal ;此時在線程池中執(zhí)行任務時獲取對象,獲取的是 創(chuàng)建線程(即 創(chuàng)建線程池中線程 的線程) 保存的對象。

如果任務使用了 ttlRunnable 修飾,此時在線程池中執(zhí)行任務時獲取對象,獲取的是 提交線程(即 提交任務到線程池 的線程) 保存的對象。而且無法獲取創(chuàng)建線程保存的對象。

4、案例(agent實現(xiàn))

需配置啟動參數(shù) -javaagent:path/to/transmittable-thread-local-2.x.x.jar

-javaagent:D:\maven\mvnRespo\com\alibaba\transmittable-thread-local\2.13.2\transmittable-thread-local-2.13.2.jar

在這里插入圖片描述

四、TaskDecorator

1、概述

使用線程池時,線程會被復用,因此線程池中的線程,執(zhí)行任務時如果要獲取 提交線程(即 提交任務到線程池 的線程) 保存的對象,還可以使用 TaskDecorator 。

看這個名稱大概就能猜出是一個裝飾器設計原理。

spring 4.3 提供 TaskDecorator

2、使用方法

主線程16個,子線程2個,執(zhí)行10次,目的是盡可能讓子線程復用。

public class TaskDecoratorTest {
    public static void main(String[] args) {
        new TaskDecoratorTest().testThreadLocal();
    }
    public void testThreadLocal() {
        ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
        ExecutorService mainThreadPool = Executors.newFixedThreadPool(16);
        ThreadPoolTaskExecutor childThreadPool = new ThreadPoolTaskExecutor();
        childThreadPool.setCorePoolSize(2);
        childThreadPool.setMaxPoolSize(2);
        childThreadPool.setTaskDecorator(runnable -> {
            int v = threadLocal.get();
            System.out.println("裝飾器中獲取到主線程=" + Thread.currentThread().getName() + " 獲取上下文=" + v);
            return () -> {
                try {
                    //重新copy傳遞給子線程
                    threadLocal.set(v);
                    runnable.run();
                } finally {
                    threadLocal.remove();
                }
            };
        });
        childThreadPool.initialize();
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            mainThreadPool.execute(() -> {
                //模擬在主線程設置上下文變量
                threadLocal.set(finalI);
                childThreadPool.execute(() -> System.out.println("子線程" + Thread.currentThread().getName() + " 獲取上下文變量=" + threadLocal.get()));
                threadLocal.remove();
            });
        }
        try {
            childThreadPool.getThreadPoolExecutor().awaitTermination(3, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

3、原理

@Override
	protected ExecutorService initializeExecutor(
			ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
		BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);
		ThreadPoolExecutor executor;
        //當線程池的裝飾器不為空時,執(zhí)行execute方法會進入這里,因為它重寫了execute方法
		if (this.taskDecorator != null) {
			executor = new ThreadPoolExecutor(
					this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
					queue, threadFactory, rejectedExecutionHandler) {
                //這里是一個代理設計模式的實現(xiàn),對execute做了一層代理
				@Override
				public void execute(Runnable command) {
                    //執(zhí)行裝飾器的邏輯,注意這段代碼是在主線程中運行
					Runnable decorated = taskDecorator.decorate(command);
					if (decorated != command) {
						decoratedTaskMap.put(decorated, command);
					}
                    //子線程真正執(zhí)行的方法(異步模塊)...初始化核心線程數(shù),核心線程滿了入隊列,隊列滿開啟至最大線程數(shù)
					super.execute(decorated);
				}
			};
		}
		else {
			executor = new ThreadPoolExecutor(
					this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
					queue, threadFactory, rejectedExecutionHandler);
		}
		if (this.allowCoreThreadTimeOut) {
			executor.allowCoreThreadTimeOut(true);
		}
		this.threadPoolExecutor = executor;
		return executor;
	}

到此這篇關于Java中的ThreadLocal詳解的文章就介紹到這了,更多相關ThreadLocal詳解內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java中靜態(tài)代理的使用與原理詳解

    Java中靜態(tài)代理的使用與原理詳解

    這篇文章主要介紹了Java中靜態(tài)代理的使用與原理詳解,代理模式是為一個對象提供一個替身,以控制對這個對象的訪問,即通過代理對象訪問目標對象.這樣做的好處是:可以在目標對象實現(xiàn)的基礎上,增強額外的功能操作,即擴展目標對象的功能,需要的朋友可以參考下
    2023-09-09
  • SpringBoot多模塊自動配置失效問題的解決方案

    SpringBoot多模塊自動配置失效問題的解決方案

    在Spring?Boot多模塊項目中,模塊間配置不生效是一個復雜但可解決的問題,尤其涉及自動配置類、依賴沖突、條件注解以及IDE配置,所以本文給大家介紹了SpringBoot多模塊自動配置失效問題的解決方案,需要的朋友可以參考下
    2025-05-05
  • slf4j與jul、log4j1、log4j2、logback的集成原理

    slf4j與jul、log4j1、log4j2、logback的集成原理

    這篇文章主要介紹了slf4j與jul、log4j1、log4j2、logback的集成原理,以及通用日志框架與具體日志實現(xiàn)系統(tǒng)的機制機制介紹,包括依賴的jar包,jar沖突處理等
    2022-03-03
  • 一個簡單的Java音樂播放器

    一個簡單的Java音樂播放器

    這篇文章主要為大家分享一個簡單的Java音樂播放器,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • springboot+kafka中@KafkaListener動態(tài)指定多個topic問題

    springboot+kafka中@KafkaListener動態(tài)指定多個topic問題

    這篇文章主要介紹了springboot+kafka中@KafkaListener動態(tài)指定多個topic問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • Java調用C++動態(tài)庫超詳細步驟講解(附源碼)

    Java調用C++動態(tài)庫超詳細步驟講解(附源碼)

    C語言因其高效和接近硬件的特性,時常會被用在性能要求較高或者需要直接操作硬件的場合,這篇文章主要介紹了Java調用C++動態(tài)庫的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-04-04
  • Java設計模式之策略模式的使用(Strategy?Pattern)

    Java設計模式之策略模式的使用(Strategy?Pattern)

    策略模式是一種行為型設計模式,用于定義一系列算法并將每個算法封裝起來,使它們可以互相替換,從而實現(xiàn)代碼的可維護性和靈活性,策略模式包含策略接口、具體策略類和上下文類,并通過將算法的選擇與使用分離,使得算法可以獨立變化
    2025-03-03
  • Java多線程的同步優(yōu)化的6種方案

    Java多線程的同步優(yōu)化的6種方案

    大家使用多線程無非是為了提高性能,在Java中,有多線程并發(fā)時,我們可以使用多線程同步的方式來解決內存一致性的問題。本文就詳細的介紹了Java多線程同步優(yōu)化,感興趣的可以了解一下
    2021-05-05
  • Java數(shù)據(jù)結構之LinkedList從鏈表到實現(xiàn)

    Java數(shù)據(jù)結構之LinkedList從鏈表到實現(xiàn)

    LinkedList是Java中常用的數(shù)據(jù)結構之一,實現(xiàn)了鏈表的特性,支持快速添加、刪除元素,可以用于實現(xiàn)隊列、棧、雙向隊列等數(shù)據(jù)結構。LinkedList的內部實現(xiàn)采用了雙向鏈表,其中每個節(jié)點都包含前驅節(jié)點和后繼節(jié)點的引用,可以直接訪問鏈表的頭尾元素
    2023-04-04
  • Java模擬實現(xiàn)HashMap算法流程詳解

    Java模擬實現(xiàn)HashMap算法流程詳解

    在java開發(fā)中,HashMap是最常用、最常見的集合容器類之一,文中通過示例代碼介紹HashMap為啥要二次Hash,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧
    2023-02-02

最新評論

砚山县| 大丰市| 邓州市| 长葛市| 海南省| 洪湖市| 钟山县| 清水县| 江安县| 多伦县| 兴业县| 安徽省| 崇阳县| 黄山市| 伊川县| 洞口县| 巴彦淖尔市| 阿克苏市| 莱州市| 保康县| 门头沟区| 广西| 雅安市| 霸州市| 青州市| 揭西县| 交口县| 宣汉县| 武功县| 莒南县| 苗栗县| 潼南县| 扶风县| 葵青区| 和田市| 仲巴县| 双峰县| 洞口县| 临猗县| 岳池县| 托克逊县|