分享个教训,因为这个小错误,我付出了三天时间来找原因,最后发现时,才如梦方醒:
上下文:用多个线程从一个ConurrentLinkedQueue里读文件名字,解析出文件名里的日期,然后把名字和日期放到另一个ConurrentLinkedQueue里,线程是这样写的:
HashMap nameDateMap = new HashMap(2);
try{
while(true)
{
if(!this.isRunning)
{
this.wait();
wakeup = System.currentTimeMillis();
}
else
{
logger.debug("Processing file : " + fileName );
dataSetID = determineType(fileName);
if(dataSetID.length() > 0)
{
nameDateMap.put("fileName", fileName);
nameDateMap.put("fileDate", parseTime(fileName));
idQueueMap.get(dataSetID).add(nameDateMap); //将文件放入该类型对应的待解码队列
}
this.setRunning(false);
}
}
}catch(InterruptedException ie)
{
logger.debug("Determine thread is interrupted: " + ie.getMessage());
}
接收者总是提示接收到了重复的名字,但是我这里logger语句明明没看到哪个文件名被重复发送了,纠结得很。最后,聪明的同事说,HashMap对象是在while循环外面声明的(第一行代码那里),但是在循环里面这个HashMap对象反复了put了key相同的两个键值对,问题可能就出在这里。于是,把第一行语句移到else里面去,接受者再也没有提示重复了,而之前看不到重复发送的迹象,是因为打印的是文件名,而不是打印的HashMap里的值。 当然,放值前调用HashMap的clear方法比重新创建对象要好。一个教训,又上了一课。如果你想对HashMap等Java集合类对象重复使用时,千万记得在重复装载值之前调用clear方法,这条教训我记得在《设计模式之禅》里作者强调过,唉~~自己体会到了!死了多少脑细胞才记住一条教训啊!