【发布时间】:2015-08-10 09:03:38
【问题描述】:
上下文
我正在构建一个简单的日志记录机制。我的 Logger 有一个名为 log(String txt) 的方法,该方法必须符合两个要求:
1- 许多线程可以访问 Logger 的对象,因此线程可以根据需要调用 log() 方法。
2- 创建 Logger 的实例/对象后,将创建一个用于存储日志的文件。但是随着时间的推移,日志文件会变大,需要创建一个新文件。
这是我想要实现的简单框架。
public class Logger {
File loggingFile;
boolean shouldBeSaved;
public void log(String msg) {
if (shouldBeSaved) {
saveLoggingFile();
}
//now write a message to loggingFile.
}
public void saveLoggingFile() {
//close the loggingFile and create a new one.
//update the shouldBeSaved flag somehow
}
}
问题
现在我面临的问题是,有时一个线程进入log() 方法并尝试发送消息,而另一个线程同时进入log() 方法并关闭文件。此时我得到一个异常,因为在第一个线程尝试写入文件时文件已关闭。因此我需要同步这个。
所以当我解决问题时,我考虑过像这样在log() 方法上同步:
public synchronized void log(String msg)
然而,需要使用这种日志机制的应用程序有很多线程,并且它需要尽快记录,因为它需要非常快速地响应。因此,像这样同步会使很多线程等待获取锁。我一直在寻找更好,更优雅的解决方案,我希望有人能提供帮助。我能想到的解决这个问题的方法是让所有其他线程等待只有在saveLoggingFile()被调用时。在saveLoggingFile() 上同步不会解决问题,因为一个线程可以尝试写入,同时另一个线程进入并尝试关闭文件。
我相信我正在寻找的这种同步具有某种模式或名称,因此如果您也能提供该模式的名称,我将不胜感激。
我不想使用日志框架,但我想知道如何解决这样的问题,因为我可能会在不同的上下文中遇到类似的问题。
【问题讨论】:
-
使用日志框架。学习如何使用库和正确记录日志会比以这种方式摸索东西更好。
-
你的 log 方法不应该直接调用 IO 操作,而是将期望记录的消息放入 Queue。异步 saveLoggingFile 从 Queue 读取消息并存储到文件(在 1 个线程中)。
-
我完全同意马特的观点。你应该使用一个登录框架来代替你处理所有这些事情,或者重新发明轮子来创建一个新的日志工具。
-
一种解决方案是让您的
log()函数将请求推送到队列而不是直接写入日志文件,并有一个后台线程为队列提供服务并写入文件。但@matt 和 Ricardo 所说的更重要。如果您不将此作为学习练习(即,如果您需要一个记录器),那么您应该使用一个已经可用的记录器。不要重新发明轮子。 -
你试过我建议的答案了吗?这将让您登录,而无需尝试记录需要阻塞的线程?
标签: java multithreading logging