我使用java logger类记录一些东西,根据某些数据,我需要将日志配置为某些路径。
假设我有以下代码:
public class LoggerLocator {
private static HashMap<String, Logger> loggerMap = new HashMap<String, Logger>();
private static int count = 0;
public Logger getLogger(String id) {
if(!LoggerLocator.loggerMap.containsKey(id)) {
configure(id);
}
return LoggerLocator.loggerMap.get(id);
}
private void configure(String id) {
Logger logger = Logger.getLogger(LoggerLocator.class.getName());
FileHandler fh = new FileHandler(String.format("/home/abc/logs/mylog_%d.log", id), true);
fileHandler.setFormatter(new MyFormatter());
logger.addHandler(fh);
}
LoggerLocator.count++;
LoggerLocator.loggerMap.put(id, logger);
}
我的问题是,当我做一些extress测试向服务器发送大量请求时,我在每个请求中打印了count变量,预计值为1,但不是这样得到值2和2个文件,名称为mylog_ {id} .log,mylog_ {id} .log.1
在创建第一个Logger并分配给HashMap并且另一个线程在LoggerLocator.loggerMap.containsKey(id)中变为false之前,logibMap是否为空?
答案 0 :(得分:1)
是的,在您创建第一个记录器之前,loggerMap
不仅可能是空的,它绝对是空的。您将变量定义为空映射。如果您希望一次将对地图的访问限制为单个帖子,则您很可能需要在某处使用syncrhonized
关键字。另外,我不建议将LoggerLocator.count++;
或LoggerLocator.loggerMap.put(id, logger);
置于任何方法之外。这让我感到反对。您的方法getLogger
和configure
也可能是静态的,您的类定义应该是abstract
,以避免能够/必须实例化LoggerLocator的实例。
答案 1 :(得分:1)
由于您基本上是在进行延迟初始化,因此您需要双重检查习语:
if (!map.containsKey(id)){
synchronized(map){
if (!map.containsKey(id)){
initialize()
}
}
}
第一次检查后锁定可确保在不执行锁定时快速进行常规访问。执行第二次检查可确保在您等待锁定时没有其他人初始化锁定。这样就可以完成一次初始化。