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

MDC在多線程中的使用方式

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

一、了解MDC

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

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

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

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

二、MDC普通使用

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

在日志配置文件中<pattern>節(jié)點中以%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操作的當前線程中獲取到值。

那是因為MDC的實現(xiàn)原理主要就是ThreadLocal,ThreadLocal只對當前線程有效。

三、多線程中的MDC

要破除ThreadLocal只對當前線程有線的方法有兩種:

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

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

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

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

有兩種方法:

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

2.lob4j和logback需要自己手動實現(xiàn),主要有兩種方法,一是手動在線程中的處理,一種是重寫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設置給子線程
 */
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 {
                // 清除子線程的,避免內存溢出,就和ThreadLocal.remove()一個原因
                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: 把當前的traceId透傳到子線程特意加的實現(xiàn)。重點就是 MDC.getCopyOfContextMap(),此方法獲取當前線程(父線程)的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;
/**
 * 線程池配置。重點就是把ThreadPoolTaskExecutor換成ThreadPoolMdcExecutor
 **/
@Configuration
public class ThreadPoolConfig {
    @Resource
    private ThreadPoolProperties threadPoolProperties;
    /**
     * 業(yè)務用到的線程池
     * @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;
    }
}

總結

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

相關文章

  • 一文詳解Spring攔截鏈的實現(xiàn)原理

    一文詳解Spring攔截鏈的實現(xiàn)原理

    在?Web應用開發(fā)中,攔截器(Interceptor)是一種非常重要的機制,能夠在請求處理的各個階段進行前置和后置處理,本文主要來探討一下?Spring?攔截鏈的實現(xiàn)原理,需要的可以了解下
    2025-01-01
  • 關于ThreadLocal的用法和說明及注意事項

    關于ThreadLocal的用法和說明及注意事項

    這篇文章主要介紹了關于ThreadLocal的用法和說明及注意事項,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • spring動態(tài)控制定時任務的實現(xiàn)

    spring動態(tài)控制定時任務的實現(xiàn)

    在實際項目中,經(jīng)常需要動態(tài)的控制定時任務,比如通過接口增加、啟動、停止、刪除定時任務,本文主要介紹了spring動態(tài)控制定時任務的實現(xiàn),感興趣的可以了解一下
    2024-01-01
  • Java中的關鍵字_動力節(jié)點Java學院整理

    Java中的關鍵字_動力節(jié)點Java學院整理

    關鍵字也稱為保留字,是指Java語言中規(guī)定了特定含義的標示符。對于保留字,用戶只能按照系統(tǒng)規(guī)定的方式使用,不能自行定義
    2017-04-04
  • Java創(chuàng)建類模式_動力節(jié)點Java學院整理

    Java創(chuàng)建類模式_動力節(jié)點Java學院整理

    這篇文章主要為大家詳細介紹了Java創(chuàng)建類模式的相關方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • Java基于TCP協(xié)議socket網(wǎng)絡編程的文件傳送的實現(xiàn)

    Java基于TCP協(xié)議socket網(wǎng)絡編程的文件傳送的實現(xiàn)

    這篇文章主要介紹了Java基于TCP協(xié)議socket網(wǎng)絡編程的文件傳送的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • Springboot+Mybatis中typeAliasesPackage正則掃描實現(xiàn)方式

    Springboot+Mybatis中typeAliasesPackage正則掃描實現(xiàn)方式

    這篇文章主要介紹了Springboot+Mybatis中typeAliasesPackage正則掃描實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Spring Cloud中關于Feign的常見問題總結

    Spring Cloud中關于Feign的常見問題總結

    這篇文章主要給大家介紹了Spring Cloud中關于Feign的常見問題,文中通過示例代碼介紹的很詳細,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-02-02
  • javaweb開發(fā)提高效率利器JRebel詳解

    javaweb開發(fā)提高效率利器JRebel詳解

    這篇文章主要介紹了javaweb開發(fā)提高效率利器JRebel詳解,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • Java8實現(xiàn)任意參數(shù)的鏈棧

    Java8實現(xiàn)任意參數(shù)的鏈棧

    這篇文章主要為大家詳細介紹了Java8實現(xiàn)任意參數(shù)的鏈棧,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-10-10

最新評論