List陷阱 写过一次很蠢的代码

ChatProtocolHandler 定义了一个list
 final Map<String, List<IoSession>> pidSessions = new ConcurrentHashMap<String, List<IoSession>>();
 
 
 //该函数设置司机在线
 private void setDidOnline(String did, IoSession session) {
if (this.didSessions.containsKey(did)) {
   List<IoSession>list = this.didSessions.get(did);
   for(IoSession ioss:list){  //这行代码老是抛出 ConcurrentModificationException 异常
   if(ioss.getId() == session.getId()){
   return ;
   }
   else{
    list.add(session);
   }
   }
}
session.setAttribute(SESSION_KEY, did);
List<IoSession>list = new ArrayList<IoSession>();
list.add(session);
this.didSessions.put(did, list);

 }

后来一运行就抛异常,,,,,,,

一直抛ConcurrentModificationException

看这个异常知道是线程安全导致,,,但是我在setDidOnline加了同步关键字,,还是没有效果。。。。。。

后来经高人指点,,,,,才知道自己犯了愚蠢的错误

for(IoSession ioss:list){   //这里迭代的时候会检查list长度是否被修改
    if(ioss.getId() == session.getId()){
    return ;
    }
    else{
      list.add(session);//这里修改了list的长度
    }
    }

单个线程却导致了这个愚蠢的问题,,,,,,,,,,亏我写了这么多年的代码,,,,,


解决方案很简单,,,将List改成ConcurrentHashMap即可。

   private void setDidOnline(String did, IoSession session) {
if (this.didSessions.containsKey(did)) {
   Map<Long, IoSession> mapSessions = this.didSessions.get(did);
   if (mapSessions.containsKey(session.getId())) {
return;
   } else {
mapSessions.put(session.getId(), session);
   }
}
session.setAttribute(SESSION_KEY, did);
Map<Long, IoSession> mapSessions = new ConcurrentHashMap<Long, IoSession>();
mapSessions.put(session.getId(), session);
this.didSessions.put(did, mapSessions);
    }


private final Map<String, Map<Long, IoSession>> didSessions = new ConcurrentHashMap<String, Map<Long, IoSession>>();


分析原因:

1 对list iterator的时候,,,list节点是不允许修改的(iterator remove方法除外)

2 没有细看Iterator源码,,因为心急只是大概猜测下是并发问题,,,这个是程序员修养的问题。遇到问题,,对一些错误不是非常明确,要心平气和把源码看通,,,这样问题就会解开


方案2:

使用CopyOnWriteArrayList 替代 arraylist,因为写array的场景很少,,,大部分都是读操作


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值