NPE在尝试在java中创建多个记录器时使用静态ThreadLocal记录器

时间:2015-01-27 06:28:59

标签: java logging thread-local

我正在尝试使用Threadlocal创建多个静态记录器,以便每个静态threadlocal将记录到具有不同消息的单独文件。以下是我的示例代码:

public class LoggerTest implements Runnable
{
    private static ThreadLocal<Logger> log=new ThreadLocal<Logger>();
    FileHandler fh;
    String str;
    public LoggerTest(int counter,String instanceName) throws SecurityException, IOException
    {
        str=instanceName;
        log.set(Logger.getLogger("Logging"+counter));
        log.get().info("m");
        fh=new FileHandler(instanceName+".log");
        fh.setFormatter(new SimpleFormatter());
        log.get().addHandler(fh);
    }
    public static void main(String[] args) throws SecurityException, IOException
    {
        Thread t1=new Thread(new LoggerTest(1, "file"+1),"Thread1");
        Thread t2=new Thread(new LoggerTest(2, "file"+2),"Thread2");
        Thread t3=new Thread(new LoggerTest(3, "file"+3),"Thread3");
        t1.start();t2.start();t3.start();
    }

    @Override
    public void run()
    {
        for (int i = 0; i < 10; i++)
        {
            log.get().info("Message"+i);
            try
            {
                Thread.sleep(5000);
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }
}

根据this,每个线程都有自己的静态ThreadLocal变量。所以我使用ThreadLocal创建了3个线程来登录不同的文件。有人可以指出我在理解静态ThreadLocal的概念时出错了吗

我的目标: 使用静态ThreadLocal实现多个记录器 TIA !!!

3 个答案:

答案 0 :(得分:2)

这是因为您需要覆盖initialValue()类的ThreadLocal方法。例如。

/** Thread local logger. */
private static final ThreadLocal<Logger> LOGGER = new ThreadLocal<Logger> () {

    @Override
    protected Logger initialValue() {
        return LoggerFactory.getLogger(ThisClass.class);
    }
};

答案 1 :(得分:1)

如果您希望字段在每个实例中都是唯一的,请不要使用静态变量!

public class LoggerTest implements Runnable
{
private final Logger log;
(...)

public LoggerTest(int counter, String instanceName) throws SecurityException, IOException
{
    log = Logger.getLogger("Logging " + counter);
    fh = new FileHandler(instanceName + ".log");
    fh.setFormatter(new SimpleFormatter());
    log.addHandler(fh);
}
(...)

@Override
public void run()
{
    (...)
    log.info("Message" + i);
}
}

相反,您还可以使用log4j框架功能进行检查:

http://logging.apache.org/log4j/1.2/manual.html

How to create different log files for different packages using same log4j logger?

Log4J loggers for different classes

log4j: Log output of a specific class to a specific appender

答案 2 :(得分:0)

我发现了我哪里出错了。以下是该工作的解决方案。

public class LoggerTest implements Runnable
{
    static int inc=0;
    private static ThreadLocal<Logger> log=new ThreadLocal<Logger>();
    FileHandler fh;
    int str;
    public LoggerTest(int counter,String instanceName) throws SecurityException, IOException
    {
        str=counter;
        fh=new FileHandler(instanceName+".log");
        fh.setFormatter(new SimpleFormatter());
    }
    public static void main(String[] args) throws SecurityException, IOException
    {
        Thread t1=new Thread(new LoggerTest(1, "file"+1),"Thread1");
        Thread t2=new Thread(new LoggerTest(2, "file"+2),"Thread2");
        Thread t3=new Thread(new LoggerTest(3, "file"+3),"Thread3");
        Thread t4=new Thread(new LoggerTest(4, "file"+4),"Thread4");
        t1.start();t2.start();t3.start();t4.start();
    }
    void meth()
    {
        log.set(Logger.getLogger("Logging"+str));
        log.get().addHandler(fh);
        for (int i = 0; i < 5; i++)
        {
            log.get().info(log.get().getName()+" Message"+i+" "+RandomStringUtils.random(str));
            try
            {
                Thread.sleep(5000);
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }
    @Override
    public void run()
    {
        this.meth();
    }
}

原因是我试图在构造函数中设置ThreadLocal。并且主线程初始化日志一次,然后它被null覆盖。因此,当我们触发Thread.start()时会创建实际的Thread。我们必须在线程启动后设置ThreadLocal。我希望这会有所帮助。