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

MDC在多線程中的使用方式

 更新時(shí)間:2023年09月22日 14:20:14   作者:EverSpring  
這篇文章主要介紹了MDC在多線程中的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

一、了解MDC

MDC(Mapped Diagnostic Context,映射調(diào)試上下文)是 slf4j提供的一種輕量級(jí)的日志跟蹤工具。

Log4j、Logback或者Log4j2等日志中最常見區(qū)分同一個(gè)請(qǐng)求的方式是通過線程名,而如果請(qǐng)求量大,線程名在相近的時(shí)間內(nèi)會(huì)有很多重復(fù)的而無法分辨,因此引出了trace-id,即在接收到的時(shí)候生成唯一的請(qǐng)求id,在整個(gè)執(zhí)行鏈路中帶上此唯一id.

MDC.java本身不提供傳遞traceId的能力,真正提供能力的是MDCAdapter接口的實(shí)現(xiàn)。

比如Log4j的是Log4jMDCAdapter,Logback的是LogbackMDCAdapter。

二、MDC普通使用

MDC.put(“trace-id”, traceId); // 添加traceId
MDC.remove(“trace-id”); // 移除traceId

在日志配置文件中<pattern>節(jié)點(diǎn)中以%X{trace-id}取出,

比如:

<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [uniqid-%X{trace-id}] %logger{50}-%line - %m%n</pattern>

以上方式,只能在做put操作的當(dāng)前線程中獲取到值。

那是因?yàn)镸DC的實(shí)現(xiàn)原理主要就是ThreadLocal,ThreadLocal只對(duì)當(dāng)前線程有效。

三、多線程中的MDC

要破除ThreadLocal只對(duì)當(dāng)前線程有線的方法有兩種:

  • 一種是JDK自帶的、ThreadLocal的擴(kuò)展類InheritableThreadLocal,子線程會(huì)拷貝父線程中的變量值
  • 一種是引入alibabatransmittable-thread-local包的TransmittableThreadLocal實(shí)現(xiàn)

據(jù)我所知,只有子線程獲取父線程,不能父線程獲取子線程的變量,如果有知道父獲取子的方法,麻煩說一下

Sl4j本身的提供的BasicMDCAdapter就是基于InheritableThreadLocal實(shí)現(xiàn)了線程間傳遞,但log4j、logback這兩個(gè)實(shí)際的日志實(shí)現(xiàn)沒有提供,log4j2提供了但默認(rèn)關(guān)閉。

1.log4j2主要是根據(jù)isThreadContextMapInheritable變量控制的,

有兩種方法:

  • log4j2.component.properties文件中配置
  • 類型模塊中定義,System.setProperty("log4j2.isThreadContextMapInherimeble", "true");

2.lob4j和logback需要自己手動(dòng)實(shí)現(xiàn),主要有兩種方法,一是手動(dòng)在線程中的處理,一種是重寫LogbackMDCAdapter。

本文以在線程池中創(chuàng)建為例

import org.slf4j.MDC;
import org.springframework.util.CollectionUtils;
import java.util.Map;
import java.util.concurrent.Callable;
/**
 * @desc: 定義MDC工具類,支持Runnable和Callable兩種,目的就是為了把父線程的traceId設(shè)置給子線程
 */
public class MdcUtil {
    public static <T> Callable<T> wrap(final Callable<T> callable, final Map<String, String> context) {
        return () -> {
            if (CollectionUtils.isEmpty(context)) {
                MDC.clear();
            } else {
                MDC.setContextMap(context);
            }
            try {
                return callable.call();
            } finally {
                // 清除子線程的,避免內(nèi)存溢出,就和ThreadLocal.remove()一個(gè)原因
                MDC.clear();
            }
        };
    }
    public static Runnable wrap(final Runnable runnable, final Map<String, String> context) {
        return () -> {
            if (CollectionUtils.isEmpty(context)) {
                MDC.clear();
            } else {
                MDC.setContextMap(context);
            }
            try {
                runnable.run();
            } finally {
                MDC.clear();
            }
        };
    }
}
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
/**
 * @desc: 把當(dāng)前的traceId透?jìng)鞯阶泳€程特意加的實(shí)現(xiàn)。重點(diǎn)就是 MDC.getCopyOfContextMap(),此方法獲取當(dāng)前線程(父線程)的traceId
 */
public class ThreadPoolMdcExecutor extends ThreadPoolTaskExecutor {
    @Override
    public void execute(Runnable task) {
        super.execute(MdcUtil.wrap(task, MDC.getCopyOfContextMap()));
    }
    @Override
    public Future<?> submit(Runnable task) {
        return super.submit(MdcUtil.wrap(task, MDC.getCopyOfContextMap()));
    }
    @Override
    public <T> Future<T> submit(Callable<T> task) {
        return super.submit(MdcUtil.wrap(task, MDC.getCopyOfContextMap()));
    }
}
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import javax.annotation.Resource;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
/**
 * 線程池配置。重點(diǎn)就是把ThreadPoolTaskExecutor換成ThreadPoolMdcExecutor
 **/
@Configuration
public class ThreadPoolConfig {
    @Resource
    private ThreadPoolProperties threadPoolProperties;
    /**
     * 業(yè)務(wù)用到的線程池
     * @return
     */
    @Bean(name = "threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolMdcExecutor();
        executor.setMaxPoolSize(threadPoolProperties.getMaxPoolSize());
        executor.setCorePoolSize(threadPoolProperties.getCorePoolSize());
        executor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
        executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
        RejectedExecutionHandler handler = ReflectUtil.newInstance(threadPoolProperties.getRejectedExecutionHandler().getClazz());
        executor.setRejectedExecutionHandler(handler);
        return executor;
    }
}

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • HashMap底層數(shù)據(jù)結(jié)構(gòu)詳細(xì)解析

    HashMap底層數(shù)據(jù)結(jié)構(gòu)詳細(xì)解析

    這篇文章主要介紹了HashMap底層數(shù)據(jù)結(jié)構(gòu)詳細(xì)解析,HashMap作為開發(fā)中常用的數(shù)據(jù)結(jié)構(gòu),也是面試中經(jīng)常被問的知識(shí)點(diǎn),因此作為開發(fā)者應(yīng)該盡可能多的理解其底層的數(shù)據(jù)結(jié)構(gòu),需要的朋友可以參考下
    2023-11-11
  • SpringBoot Freemarker基礎(chǔ)配置與使用方式

    SpringBoot Freemarker基礎(chǔ)配置與使用方式

    文章主要介紹了在Spring Boot項(xiàng)目中使用FreeMarker模板引擎的基礎(chǔ)配置、使用方法和注意事項(xiàng),包括依賴引入、配置文件設(shè)置、數(shù)據(jù)類型調(diào)用、運(yùn)算符支持、時(shí)間格式轉(zhuǎn)換、邏輯表達(dá)式等
    2026-05-05
  • 使用logstash同步mysql數(shù)據(jù)到elasticsearch實(shí)現(xiàn)

    使用logstash同步mysql數(shù)據(jù)到elasticsearch實(shí)現(xiàn)

    這篇文章主要為大家介紹了使用logstash同步mysql數(shù)據(jù)到elasticsearch實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • 使用System.exit()來優(yōu)雅地終止SpringBoot項(xiàng)目的代碼示例

    使用System.exit()來優(yōu)雅地終止SpringBoot項(xiàng)目的代碼示例

    System.exit() 方法是 Java 中用于退出程序的方法,它接受一個(gè)整數(shù)參數(shù),通常被用來指示程序的退出狀態(tài),本文給大家介紹了如何使用System.exit()來優(yōu)雅地終止SpringBoot項(xiàng)目,需要的朋友可以參考下
    2024-08-08
  • java實(shí)現(xiàn)輸出文件夾下某個(gè)格式的所有文件實(shí)例代碼

    java實(shí)現(xiàn)輸出文件夾下某個(gè)格式的所有文件實(shí)例代碼

    這篇文章主要介紹了java實(shí)現(xiàn)輸出文件夾下某個(gè)格式的所有文件,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-06-06
  • 使用SpringBoot注解方式處理事務(wù)回滾實(shí)現(xiàn)

    使用SpringBoot注解方式處理事務(wù)回滾實(shí)現(xiàn)

    這篇文章主要介紹了使用SpringBoot注解方式處理事務(wù)回滾實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Java生態(tài)中的NLP框架詳解

    Java生態(tài)中的NLP框架詳解

    Java生態(tài)系統(tǒng)中提供了多個(gè)強(qiáng)大的自然語言處理(NLP)框架,今天通過本文給大家介紹Java生態(tài)中的NLP框架,感興趣的朋友一起看看吧
    2025-06-06
  • Java中List集合去重的幾種方式詳細(xì)解析

    Java中List集合去重的幾種方式詳細(xì)解析

    這篇文章主要介紹了Java中List集合去重的幾種方式詳細(xì)解析,在日常的業(yè)務(wù)開發(fā)中,偶爾會(huì)遇到需要將 List 集合中的重復(fù)數(shù)據(jù)去除掉的場(chǎng)景,那么今天我們來看看幾種LIst集合去重的方式,需要的朋友可以參考下
    2023-11-11
  • 關(guān)于Future機(jī)制原理及解析

    關(guān)于Future機(jī)制原理及解析

    這篇文章主要介紹了關(guān)于Future機(jī)制原理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Java elasticsearch安裝以及部署教程

    Java elasticsearch安裝以及部署教程

    這篇文章主要介紹了elasticsearch安裝以及部署教程,內(nèi)涵詳細(xì)的圖文展示與案例介紹,能夠幫助你從0成功部署這個(gè)框架,需要的朋友可以參考下
    2021-06-06

最新評(píng)論

颍上县| 罗山县| 威信县| 华安县| 柳州市| 顺平县| 天峨县| 贵德县| 三台县| 蒙山县| 武穴市| 正镶白旗| 客服| 台中市| 甘孜县| 万全县| 凤冈县| 饶河县| 土默特右旗| 奉化市| 荆门市| 禄丰县| 阿合奇县| 徐汇区| 南雄市| 来凤县| 重庆市| 康马县| 金塔县| 焉耆| 准格尔旗| 嘉兴市| 肥东县| 霍山县| 汾阳市| 日土县| 甘德县| 邓州市| 鹰潭市| 绥滨县| 固原市|