- -----转自:http://blog.csdn.net/pengchang_1981/article/details/8091562
- // 定义的一个map常量
- private static final Map<AlarmInfo, String> PLAN_ALARM_MAP = new LinkedHashMap<AlarmInfo, String>();
- // 下面是处理过程
- synchronized (PLAN_ALARM_MAP) {
- logger.infoT("PLAN_ALARM_MAP size " + PLAN_ALARM_MAP.size());
- Set<AlarmInfo> set = PLAN_ALARM_MAP.keySet();
- for (AlarmInfo alarmInfo : set) {
- if (!checkContinueAlarm(alarmInfo,
- PLAN_ALARM_MAP.get(alarmInfo))) {
- logger.infoT("clear planTask alarm!");
- // 清除告警信息
- manageAlarm(alarmInfo, mesg, true);
- PLAN_ALARM_MAP.remove(alarmInfo);
- // 记录下来,后面删除
- // alarmDelete.add(alarmInfo);
- }
- }
- }
看出来了吧,和List一样,在循环迭代过程中是不能修改或者删除Map的key的,会引发java.util.concurrentmodificationexception,很有趣的是,就像api说的,在大部分情况下会引起该异常,但有时候不会出异常,至于这个原因没深入研究源码,就暂且不论。发现了异常,就要满足在循环迭代Map的keySet的过程中删除map中的符合条件key的别的解决办法,在网上查了下找到两套都能实现的办法:
1 将要删除的key存到一个List中,在遍历完map的keySet后,再迭代这个存放删除key的List,逐一删除!
2 采用Iterator迭代,在迭代遇到需要删除的key时,采用迭代器的remove()方法删除,也可以避免出现异常!
方案1的解决代码如下:
- private static final Map<AlarmInfo, String> PLAN_ALARM_MAP = new LinkedHashMap<AlarmInfo, String>();
- synchronized (PLAN_ALARM_MAP) {
- logger.infoT("PLAN_ALARM_MAP size " + PLAN_ALARM_MAP.size());
- Set<AlarmInfo> set = PLAN_ALARM_MAP.keySet();
- List<AlarmInfo> alarmDelete = new ArrayList<AlarmInfo>();
- for (AlarmInfo alarmInfo : set) {
- if (!checkContinueAlarm(alarmInfo,
- PLAN_ALARM_MAP.get(alarmInfo))) {
- logger.infoT("clear planTask alarm!");
- // 清除告警信息
- manageAlarm(alarmInfo, mesg, true);
- // 记录下来,后面删除
- alarmDelete.add(alarmInfo);
- }
- }
- // 进行删除
- for (AlarmInfo deleteAlarm : alarmDelete) {
- PLAN_ALARM_MAP.remove(deleteAlarm);
- }
- }
- private static final Map<AlarmInfo, String> PLAN_ALARM_MAP = new LinkedHashMap<AlarmInfo, String>();
- synchronized (PLAN_ALARM_MAP) {
- logger.infoT("PLAN_ALARM_MAP size " + PLAN_ALARM_MAP.size());
- Set<AlarmInfo> set = PLAN_ALARM_MAP.keySet();
- AlarmInfo tempAlarmInfo = null;
- for (Iterator<AlarmInfo> itr = set.iterator(); itr.hasNext();) {
- tempAlarmInfo = itr.next();
- if (!checkContinueAlarm(tempAlarmInfo,
- PLAN_ALARM_MAP.get(tempAlarmInfo))) {
- logger.infoT("clear planTask alarm!");
- // 清除告警信息
- manageAlarm(tempAlarmInfo, mesg, true);
- itr.remove();
- }
- }
- }
参考文献:
http://yulimeander.i.sohu.com/blog/view/142269299.htm
http://swincle.iteye.com/blog/746980
以下是个人理解
查看了一下itertor.remove()的源代码 和map.remove()的源代码
itertor.remove()部分源代码
<span style="color:#ff0000;"> Entry<K,V> current; // current entry</span>
public void remove() {
if (current == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Object k = current.key;
<span style="color:#ff0000;">current = null;</span>
HashMap.this.<span style="color:#ff0000;">removeEntryForKey(k)</span>;
expectedModCount = modCount;
}
map.remove()部分源代码
public V remove(Object key) {
Entry<K,V> e = <span style="color:#ff0000;">removeEntryForKey(key);</span>
return (e == null ? null : e.value);
}
可以看到 两者其实都是调用map的 removeEntryForKey(key) 方法去进行移除操作
区别是itertor.remove()在调用removeEntryForKey(key);前做了current = null 也就是释放了entry对map的引用
map.remove()方法却没有执行这步操作
所以当通过entryset去对map进行remove()操作时 因为entry还留有map的引用 所以操作失败
-------version1.0 2015.1.28