秦皇岛做网站多少钱,jsp如何进行购物网站开发,秦皇岛市中医院,网络营销的市场背景log4j日志配置文件中的%X{TransId}是怎么动态获取值的
在Log4j中#xff0c;%X{TransId} 是用来从MDC#xff08;Mapped Diagnostic Context#xff09;中获取值的占位符。MDC 是 Log4j 提供的一种机制#xff0c;用于在同一个线程的不同日志记录中传递上下文信息。通过 M…log4j日志配置文件中的%X{TransId}是怎么动态获取值的
在Log4j中%X{TransId} 是用来从MDCMapped Diagnostic Context中获取值的占位符。MDC 是 Log4j 提供的一种机制用于在同一个线程的不同日志记录中传递上下文信息。通过 MDC你可以在日志中添加一些动态的上下文信息比如事务ID、用户ID等。
要动态设置 TransId 的值你需要在代码中使用 MDC.put 方法。以下是一个示例
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;public class Log4jExample {private static final Logger logger LogManager.getLogger(Log4jExample.class);public static void main(String[] args) {// 设置TransId的值ThreadContext.put(TransId, 12345);// 记录日志logger.info(This is a log message with TransId.);// 清除TransId的值ThreadContext.clearMap();}
}在上面的代码中我们使用 ThreadContext.put(TransId, 12345) 来设置 TransId 的值。然后在日志配置文件中使用 %X{TransId} 占位符来引用这个值。
例如log4j2.xml 配置文件可以这样配置
Configuration statusWARNAppendersConsole nameConsole targetSYSTEM_OUTPatternLayout pattern%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg %X{TransId}%n//Console/AppendersLoggersRoot levelinfoAppenderRef refConsole//Root/Loggers
/Configuration在这个配置中%X{TransId} 会被替换为 ThreadContext 中 TransId 的值即 12345。
总结通过在代码中使用 ThreadContext.put(TransId, value) 方法设置 TransId 的值然后在日志配置文件中使用 %X{TransId} 占位符来引用这个值从而实现动态获取和记录 TransId。
在Log4j 2中ThreadContext 是用来替代 Log4j 1.x 中的 MDC 的。对于 Log4j 1.x你需要使用 MDC.put 方法来设置上下文信息。以下是使用 Log4j 1.x 的示例
import org.apache.log4j.Logger;
import org.apache.log4j.MDC;public class Log4jExample {private static final Logger logger Logger.getLogger(Log4jExample.class);public static void main(String[] args) {// 设置TransId的值MDC.put(TransId, 12345);// 记录日志logger.info(This is a log message with TransId.);// 清除TransId的值MDC.clear();}
}在上面的代码中我们使用 MDC.put(TransId, 12345) 来设置 TransId 的值。然后在日志配置文件中使用 %X{TransId} 占位符来引用这个值。
例如log4j.properties 配置文件可以这样配置
log4j.rootLoggerINFO, Consolelog4j.appender.Consoleorg.apache.log4j.ConsoleAppender
log4j.appender.Console.layoutorg.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1} - %m %X{TransId}%n在这个配置中%X{TransId} 会被替换为 MDC 中 TransId 的值即 12345。
总结对于 Log4j 1.x通过在代码中使用 MDC.put(TransId, value) 方法设置 TransId 的值然后在日志配置文件中使用 %X{TransId} 占位符来引用这个值从而实现动态获取和记录 TransId。对于 Log4j 2.x使用 ThreadContext.put 方法来实现相同的功能。
ThreadLocal 是 Java 提供的一种机制用于在每个线程中存储独立的变量副本。它可以确保变量在多线程环境下的线程安全性而不需要显式的同步。每个线程都可以独立地修改自己的副本而不会影响其他线程的副本。
ThreadLocal 的基本原理 独立副本每个线程都有一个独立的变量副本这些副本存储在 ThreadLocal 对象中。每个线程对其副本的修改不会影响其他线程的副本。 内部存储ThreadLocal 通过 Thread 类中的一个内部 ThreadLocalMap 来存储每个线程的变量副本。ThreadLocalMap 是一个自定义的哈希表键是 ThreadLocal 对象值是线程的变量副本。 访问机制当线程访问 ThreadLocal 变量时ThreadLocal 会根据当前线程获取对应的变量副本。如果当前线程没有对应的副本ThreadLocal 会创建一个新的副本并存储在 ThreadLocalMap 中。
ThreadLocal 的主要方法
get()返回当前线程的变量副本。如果当前线程没有对应的副本则调用 initialValue() 方法创建一个新的副本。set(T value)设置当前线程的变量副本。remove()移除当前线程的变量副本防止内存泄漏。
示例代码
以下是一个简单的示例展示了如何使用 ThreadLocal
public class ThreadLocalExample {// 创建一个ThreadLocal变量private static ThreadLocalInteger threadLocal ThreadLocal.withInitial(() - 0);public static void main(String[] args) {// 创建两个线程Thread thread1 new Thread(() - {for (int i 0; i 5; i) {threadLocal.set(threadLocal.get() 1);System.out.println(Thread.currentThread().getName() - threadLocal.get());}});Thread thread2 new Thread(() - {for (int i 0; i 5; i) {threadLocal.set(threadLocal.get() 1);System.out.println(Thread.currentThread().getName() - threadLocal.get());}});thread1.start();thread2.start();}
}在这个示例中每个线程都有一个独立的 ThreadLocal 变量副本互不干扰。
内部实现
ThreadLocal 的内部实现主要依赖于 ThreadLocalMap这是一个自定义的哈希表存储在每个线程的 Thread 对象中。以下是一些关键点 ThreadLocalMapThreadLocalMap 是 ThreadLocal 的静态内部类用于存储每个线程的变量副本。它使用 ThreadLocal 对象作为键变量副本作为值。 EntryThreadLocalMap 中的每个条目是一个 Entry 对象包含一个弱引用的 ThreadLocal 键和一个强引用的值。 垃圾回收由于 ThreadLocal 键是弱引用当 ThreadLocal 对象被垃圾回收时ThreadLocalMap 中对应的条目会被自动清除防止内存泄漏。
内存泄漏问题
使用 ThreadLocal 时需要注意内存泄漏问题。由于 ThreadLocalMap 中的键是弱引用但值是强引用如果不显式调用 remove() 方法可能会导致内存泄漏。因此建议在使用完 ThreadLocal 变量后显式调用 remove() 方法清除变量副本。
threadLocal.remove();总结ThreadLocal 提供了一种在多线程环境下存储和访问独立变量副本的机制确保线程安全性。其内部通过 ThreadLocalMap 实现每个线程都有一个独立的变量副本。使用时需要注意内存泄漏问题建议在使用完后显式调用 remove() 方法清除变量副本。
ThreadLocalMap 是 ThreadLocal 类的一个静态内部类用于存储每个线程的变量副本。它是 ThreadLocal 实现的核心部分。ThreadLocalMap 通过在每个线程的 Thread 对象中维护一个哈希表来实现这一功能。
ThreadLocalMap 的结构
ThreadLocalMap 是一个自定义的哈希表包含以下几个关键部分 EntryThreadLocalMap 中的每个条目是一个 Entry 对象。Entry 是 ThreadLocalMap 的静态内部类包含一个弱引用的 ThreadLocal 键和一个强引用的值。 static class Entry extends WeakReferenceThreadLocal? {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal? k, Object v) {super(k);value v;}
}TableThreadLocalMap 使用一个数组 table 来存储 Entry 对象。数组的大小是2的幂次方以便于哈希冲突的处理。 private Entry[] table;ThresholdThreadLocalMap 维护一个阈值 threshold用于控制何时进行扩容。默认情况下阈值是数组大小的2/3。 private int threshold;ThreadLocalMap 的主要方法 set()将值存储到 ThreadLocalMap 中。如果键已经存在则更新值如果键不存在则插入新的条目。 private void set(ThreadLocal? key, Object value) {Entry[] tab table;int len tab.length;int i key.threadLocalHashCode (len - 1);for (Entry e tab[i];e ! null;e tab[i nextIndex(i, len)]) {ThreadLocal? k e.get();if (k key) {e.value value;return;}if (k null) {replaceStaleEntry(key, value, i);return;}}tab[i] new Entry(key, value);int sz size;if (!cleanSomeSlots(i, sz) sz threshold)rehash();
}get()从 ThreadLocalMap 中获取值。如果键存在则返回对应的值如果键不存在则返回 null。 private Object getEntry(ThreadLocal? key) {int i key.threadLocalHashCode (table.length - 1);Entry e table[i];if (e ! null e.get() key)return e.value;elsereturn getEntryAfterMiss(key, i, e);
}remove()从 ThreadLocalMap 中移除键值对。 private void remove(ThreadLocal? key) {Entry[] tab table;int len tab.length;int i key.threadLocalHashCode (len - 1);for (Entry e tab[i];e ! null;e tab[i nextIndex(i, len)]) {if (e.get() key) {e.clear();expungeStaleEntry(i);return;}}
}内存泄漏问题
由于 ThreadLocalMap 中的键是弱引用当 ThreadLocal 对象被垃圾回收时键会变成 null但值仍然存在。这可能导致内存泄漏。因此建议在使用完 ThreadLocal 变量后显式调用 remove() 方法清除变量副本。
threadLocal.remove();总结
ThreadLocalMap 是 ThreadLocal 的静态内部类用于存储每个线程的变量副本。Entry 是 ThreadLocalMap 的静态内部类包含一个弱引用的 ThreadLocal 键和一个强引用的值。ThreadLocalMap 使用一个数组 table 来存储 Entry 对象并通过哈希算法和线性探测解决哈希冲突。主要方法 包括 set()、get() 和 remove()用于存储、获取和移除键值对。内存泄漏问题由于键是弱引用值是强引用建议在使用完 ThreadLocal 变量后显式调用 remove() 方法清除变量副本。