欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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ù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • SpringBoot默認使用HikariDataSource數(shù)據(jù)源方式

    SpringBoot默認使用HikariDataSource數(shù)據(jù)源方式

    這篇文章主要介紹了SpringBoot默認使用HikariDataSource數(shù)據(jù)源方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • JAVA錯誤:'無效目標發(fā)行版?17'的解決方案

    JAVA錯誤:'無效目標發(fā)行版?17'的解決方案

    這篇文章主要給大家介紹了關于JAVA錯誤:'無效目標發(fā)行版?17'的解決方案,文中通過圖文介紹的非常詳細,對大家學習或使用java具有一的的參考學習價值,需要的朋友可以參考下
    2022-09-09
  • springboot?@Validated的概念及示例實戰(zhàn)

    springboot?@Validated的概念及示例實戰(zhàn)

    這篇文章主要介紹了springboot?@Validated的概念以及實戰(zhàn),使用?@Validated?注解,Spring?Boot?應用可以有效地實現(xiàn)輸入驗證,提高數(shù)據(jù)的準確性和應用的安全性,本文結合實例給大家講解的非常詳細,需要的朋友可以參考下
    2024-04-04
  • java抓取12306信息實現(xiàn)火車余票查詢示例

    java抓取12306信息實現(xiàn)火車余票查詢示例

    這篇文章主要介紹了java抓取12306信息實現(xiàn)火車余票查詢示例,需要的朋友可以參考下
    2014-04-04
  • 圖解Java?ReentrantLock公平鎖和非公平鎖的實現(xiàn)

    圖解Java?ReentrantLock公平鎖和非公平鎖的實現(xiàn)

    ReentrantLock是Java并發(fā)中十分常用的一個類,具備類似synchronized鎖的作用。但是相比synchronized,?它具備更強的能力,同時支持公平鎖和非公平鎖。本文就來聊聊ReentrantLock公平鎖和非公平鎖的實現(xiàn),需要的可以參考一下
    2022-10-10
  • Java多線程繼承Thread類詳解

    Java多線程繼承Thread類詳解

    Java多線程的兩種實現(xiàn)方式:繼承Thread類 & 實現(xiàn)Runable接口,今天我們來學習下繼承Thread類,希望大家能夠喜歡
    2016-06-06
  • Java中Word與PDF轉換為圖片的方法詳解

    Java中Word與PDF轉換為圖片的方法詳解

    這篇文章主要為大家詳細介紹了如何使用Java實現(xiàn)將Word與PDF轉換為圖片,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2024-10-10
  • MyBatisPlus中事務處理的實現(xiàn)

    MyBatisPlus中事務處理的實現(xiàn)

    本文主要介紹了MyBatisPlus中事務處理的實現(xiàn),包括事務的開啟、提交、回滾等操作,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-07-07
  • 詳解Spring @Autowired 注入小技巧

    詳解Spring @Autowired 注入小技巧

    這篇文章主要介紹了詳解Spring @Autowired 注入小技巧,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • SpringMVC整合SpringSession 實現(xiàn)sessiong

    SpringMVC整合SpringSession 實現(xiàn)sessiong

    這篇文章主要介紹了SpringMVC整合SpringSession 實現(xiàn)session的實例代碼,本文通過實例相結合的形式給大家介紹的非常詳細,需要的朋友參考下吧
    2018-04-04

最新評論