在java中,是否可以在线程中保存本地变量?

时间:2013-08-05 13:04:53

标签: java servlets

我正在尝试使用log4j从基于servlet的java应用程序进行一些日志记录。我想记录额外的信息,如用户ID等。有没有办法把局部变量放在一个线程?并且在记录时,是否可以获取当前线程,并获取设置的局部变量?

4 个答案:

答案 0 :(得分:7)

不是直接使用线程本地存储,而是使用Log4j的NDCMDC(嵌套和映射的诊断上下文)。它们已经是线程本地的,您可以使用%x%X模式将它们的数据包含在日志消息中,这样就不需要将数据显式地从线程本地上下文中提取出来以将其包含在日志中消息。

答案 1 :(得分:6)

Log4J MDC方法

这是如何使用MDC

public class MdcExample implements Runnable {
    private static final Logger logger  = Logger.getLogger(MdcExample.class);

    public static void main(final String[] args) {
        final MdcExample threadLocalExample = new MdcExample();

        final Thread thread1 = new Thread(threadLocalExample);
        final Thread thread2 = new Thread(threadLocalExample);
        final Thread thread3 = new Thread(threadLocalExample);

        thread1.start(); thread2.start(); thread3.start();
    }

    @Override
    public void run() {

        while (true) {
            MDC.put("random", "" + Math.random());

            try {
                logger.info("My log message, prefixed with MDC");
                TimeUnit.SECONDS.sleep(1);
            }
            catch (final InterruptedException e) {
            }
        }
    }
}

Log4J设置:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

    <!-- Appenders -->
    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p %X{random}:- %m%n" />
        </layout>
    </appender> 

    <!-- Root Logger -->
    <root>
        <priority value="info" />
        <appender-ref ref="console" />
        <appender-ref ref="file" />
    </root>

</log4j:configuration>

线程本地方法(如果您的Businesslogic需要它)

如果您想将值(如用户)本地存储到线程,请使用ThreadLocal

import java.util.concurrent.TimeUnit;

public class ThreadLocalExample implements Runnable {
    ThreadLocal<Double> myRandom    = new ThreadLocal<>();

    public static void main(final String[] args) {
        final ThreadLocalExample threadLocalExample = new ThreadLocalExample();

        final Thread thread1 = new Thread(threadLocalExample);
        final Thread thread2 = new Thread(threadLocalExample);
        final Thread thread3 = new Thread(threadLocalExample);

        thread1.start(); thread2.start(); thread3.start();
    }

    @Override
    public void run() {

        this.myRandom.set(Math.random());

        while (true) {
            System.out.println(Thread.currentThread().getId() + " " + this.myRandom.get());

            try {
                TimeUnit.SECONDS.sleep(1);
            }
            catch (final InterruptedException e) {
            }
        }
    }
}

http://docs.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html

将线程ID添加到log4j输出

关于你的log4j问题,你可以使用th t - 占位符作为主题名称:

这是您可以使用的示例Appender:

<appender name="console" class="org.apache.log4j.ConsoleAppender">
    <param name="Target" value="System.out" />
    <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%5p %d{ISO8601} [%t][%x] %c - %m%n" />
    </layout>
</appender>

http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html

答案 2 :(得分:2)

ThreadLocal是要走的路。 ThreadLocal提供了保存不在线程之间共享的变量的功能,并且在线程的整个生命周期中都可用。

ThreadLocal本功能的本质可以帮助您摆脱同步块。

答案 3 :(得分:0)

您应该使用MDC。您可以存储命名属性,然后直接以日志格式引用它们。有关示例,请参阅What is the difference between Log4j's NDC and MDC facilities?