【问题标题】:Executing each logging request on a different thread在不同的线程上执行每个日志记录请求
【发布时间】:2015-01-22 08:57:20
【问题描述】:

我已经编写了一个基于观察者设计模式的自定义 MyLogger 库。我想要实现的是:每次我调用writeLog(LOG_LEVEL,"Text") 方法时,我都希望它在一个新线程中执行。有人可以建议实现这一目标的方法。至于我应该在哪里创建线程。

这就是我的 Logger 调用的外观。

public class Logger extends Subject{
     void writeLog(String type, String message)
        {       setData(message);
                notifyy(type);
        }

}

这就是我调用 writeLog 的方式

appLogger.writeLog("ERROR", "This is error");

【问题讨论】:

标签: java multithreading observer-pattern


【解决方案1】:

您可以像这样使用 Producer-Consumer-Pattern:

public class Logger {

    /**
     * The ExecutorService runs the Thread that processes the logs.
     */
    private final ExecutorService loggingService = Executors.newSingleThreadExecutor();

    /**
     * A queue that contains the logs.
     */
    final BlockingQueue<YourLogObject> logs = new LinkedBlockingQueue<>();

    /**
     * Creates a new Logger object and starts the Thread that processes the logs.
     */
    public Logger() {
        loggingService.submit(new Runnable() {

            @Override
            public void run() {
                try {
                    for (;;) {
                        final YourLogObject log = logs.take();

                        // setData(log.getMessage());
                        // notify(log.getLevel());
                    }
                } catch (final InterruptedException e) {
                    e.printStackTrace();
                    return;
                }
            }

        });
    }

    /**
     * Creates a new YourLogObject from the given parameters and puts it at the end of the queueu.
     */
    public void writeLog(final String level, final String message) {
        final YourLogObject log = new YourLogObject(level, message);

        try {
            logs.put(log);
        } catch (final InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 
     */
    public void shutdown() {
        loggingService.shutdownNow();
    }

}

public class YourLogObject {

    private final String level;

    private final String message;

    public YourLogObject(final String level, final String message) {
        this.level = level;
        this.message = message;
    }

    public String getLevel() {
        return level;
    }

    public String getMessage() {
        return message;
    }

}

【讨论】:

  • 感谢您的回复。您能否建议这在概念上与斯蒂芬的答案有何不同
  • 使用这个解决方案,您只有一个后台线程,它一直在运行。你有一个消息队列。 writeLog() 方法将新日志放入此队列,后台线程不断将消息从队列中取出。在 Stephan 的方法中,每次调用 writeLog() 都会创建一个线程。这可能开销很大。
【解决方案2】:

您可以使用ExecutorService

// Somewhere in your logging framework
ExecutorService service = Executors.new...(); // Choose the one you want
...

public MessageRelayingTask implements Runnable {
    // private fields
    ...

    public MessageRelayingTask(String type, String message) {
         ...
    }

    @Override
    public void run() {
        setData(message);
        notifyy(type);
    }     
}

public class Logger extends Subject implements Runnable {
    void writeLog(String type, String message) {
        service.submit(new MessageRelayingTask(type, message));
    }
}

一些帮助您入门的建议:

【讨论】:

  • 非常感谢斯蒂芬的回复。还有其他方法吗?如果是,您能否建议以一种方式比其他方式做的优势。
  • 但是为什么每条消息都有一个新线程?似乎开销很大。从共享队列中获取的单个后台线程还不够吗?
  • @Stephan .. 上面的代码有一些小问题。 run() 中的“消息”和“类型”..我们如何将它们传递到那里?当前出现“消息无法解析为变量”错误
  • @Thilo 这是一种简单的方法......只是为了让 OP 开始。这里没有足够的空间来描述一个完整的系统。
  • @Thilo。没听懂……当您说“从共享队列中获取的单个后台线程不够吗?”时,我可以请您详细说明一下吗?我是并发新手。
猜你喜欢
  • 1970-01-01
  • 2016-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-19
  • 2019-04-20
  • 2012-01-11
  • 1970-01-01
相关资源
最近更新 更多