2014-12-05 28 views
0

我正在使用java記錄器類來記錄一些東西,並根據某些數據我需要將日誌配置到某些路線。記錄器在HashMap

讓說我有下面的代碼:

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測試發送大量請求到服務器,我印在每個請求的計數變量,從而有望具有值1,而不是獲取名稱爲mylog_ {id} .log,mylog_ {id} .log.1的2和2個文件的值

可能是在創建第一個記錄之前loggerMap爲空記錄器和分配給HashMap和另一個線程在LoggerLocator.loggerMap.containsKey(id)中變爲false?

回答

1

是的,在創建第一個記錄器之前,不僅有可能loggerMap是空的,它絕對是空的。您將該變量定義爲空映射。如果您想限制一次訪問地圖到單個線索,則很可能需要在某處使用syncrhonized關鍵字。此外,我不建議將LoggerLocator.count++;LoggerLocator.loggerMap.put(id, logger);以外的任何方法。這讓我感到反感。您的方法getLoggerconfigure也應該是靜態的,並且您的類定義應爲abstract,以避免能夠/不得不實例化LoggerLocator的實例。

1

因爲你基本上是在做延遲初始化,你想仔細檢查成語:

if (!map.containsKey(id)){ 
    synchronized(map){ 
     if (!map.containsKey(id)){ 
      initialize() 
     } 
    } 
} 

以鎖定第一檢查確保定期訪問快,鎖沒有拍攝之後。執行第二次檢查可確保在您等待鎖定時沒有其他人已初始化鎖定。這樣你就可以得到一個初始化。