vb中遍历collection:有关Collection中的安全

以前听老师在讲Collection集合框架时候说到了Iterator来单线程修改和删除集合里面数据意思是Iterator来操作删除和修改集合里面数据感觉也没什么关系啊但是科学态度永远严谨就在我兴奋地时候问题突如其来:
问题场景: 在Session在事务后立即关闭和Lazy为False另外查询缓存Cache未显式打开情况下并且由于hibernate list在实际情况下是不开启查询缓存CacheIterator开启,现在我在此情况下执行次性查询加载外键对象数据那么要显式迭代并外键中以便生成相应数据但是就是在这里出现了问题给我抛了个大大ConcurrentModicationException以前我也用过显式来加载外键对象数据但是没有遇到过这种问题到底是什么导致呢?我现在就这个问题来分析
//以前场景
List<Sightholders> .gif' />Sightholders = null;
.gif' />Sightholders = session.createQuery(
"from Sightholders order by sightholdersId asc")
.FirstResult(pageSize * (pageNo - 1)).MaxResults(
pageSize).list;
.out.prln("长度" + .gif' />Sightholders.size);
for (Iterator<Sightholders> c = .gif' />Sightholders.iterator; c
.hasNext;) {
c.next.getStafferId;
}

//当前场景
List sigsCheckInfo = null;
sigsCheckInfo = session.createQuery(sigsHQL)
.Parameter(0, dateStr)
.Parameter(1, sigsId)
.FirstResult(pageSize * (pageNo - 1))
.MaxResults(pageSize)
.list;
boolean isScof = false;
boolean isRcof = false;

for(Iterator iter = sigsCheckInfo.iterator ;iter.hasNext;){
Object obj = iter.next;

((obj instanceof SupplierCheckOutForm) || isScof){
SupplierCheckOutForm scof = (SupplierCheckOutForm)obj;
scof.getSupplierId.getSightholdersName;
scof.getFpreparer.getName;
isScof= true;

} (obj instanceof ReceivingCheckOutForm || isRcof){
ReceivingCheckOutForm rcof = (ReceivingCheckOutForm)obj;
rcof.getReceivingId.getSightholdersName;
rcof.getFpreparer.getName;
isRcof= true;
}

}

我们知道在Iterator操作时候是单线程这样是确保在多客户使用同个数据集合时候避免出现线程区别步情况这样对于性能还是数据安全和数据完整来说都是毁灭性打击那么我分析了这两段代码本质上没什么区别但是我们可以看到个明显区别那就是泛型引入在场景中是指定了泛型而场景 2没有这样就导致了我在场景 2需要存入可能是区别对象当我们以Object类型来读取出数据库中数据后并没有指定相应数据类型从而导致在Iterator操作时候出现了修改数据类型种操作从Object脱离到可能两种对象所以这个时候出现了修改这个时候就会威胁到Iterator 本质安全所以给了我个大大 ConcurrentModicationException
我们来分析下这个异常:java.util.ConcurrentModicationException
导致抛出此异常原因是:对集合类进行迭代时候对里面内容进行了修改即不能用他们Api来修改集合里面内容这样会导致出现这样问题
下面我对场景 2代码做了如下修改切正常:
((obj instanceof SupplierCheckOutForm) || isScof){
SupplierCheckOutForm scof = (SupplierCheckOutForm)obj;
scof.getSupplierId.getSightholdersName;
scof.getFpreparer.getName;
sigsCheckInfo.remove(obj);
sigsCheckInfo.add(scof);

// iter.remove;
isScof= true;

} (obj instanceof ReceivingCheckOutForm || isRcof){
ReceivingCheckOutForm rcof = (ReceivingCheckOutForm)obj;
rcof.getReceivingId.getSightholdersName;
rcof.getFpreparer.getName;
sigsCheckInfo.remove(obj);
sigsCheckInfo.add(rcof);
// iter.remove;
isRcof= true;
}
注意在红色类对象RCOF 和SCOF中需要添加HasCode和Equals思路方法,否则会导致删除不了
也可以使用如下修改:
for(Iterator iter = sigsCheckInfo2.iterator ;iter.hasNext;){
Object obj = iter.next;

((obj instanceof SupplierCheckOutForm) || isScof){
SupplierCheckOutForm scof = (SupplierCheckOutForm)obj;
scof.getSupplierId.getSightholdersName;
scof.getFpreparer.getName;
sigsCheckInfo.add(scof);
iter.remove;
isScof= true;

} (obj instanceof ReceivingCheckOutForm || isRcof){
ReceivingCheckOutForm rcof = (ReceivingCheckOutForm)obj;
rcof.getReceivingId.getSightholdersName;
rcof.getFpreparer.getName;
sigsCheckInfo.add(rcof);
iter.remove;
isRcof= true;
}

}
在此我用了两个List来存储和转换,也相当于数据相互转移当然这里返回最好是LinkedList链表操作增加删除快然后通过Iterator安全remove操作对原始Iterator对象进行抽取.
当前在另外场景中也有出现此问题例如下面这个例子:
public void Reparation(Reparation reparation) {
for (Iterator it = this.reparations.iterator; it.hasNext;) {
Reparation repa = (Reparation) it.next;
(repa.getId reparation.getId) {
this.reparations.remove(repa);
this.reparations.add(reparation);
}
}
}注意在此代码中Reparation reparation 为集合类例如ArrayList由于在Iterator中对Arraylist进行了remove操作所以我们发现报了异常可以采取下列方式来进行修改:
public void Reparation(Reparation reparation) {
boolean flag = false;
for (Iterator it = this.reparations.iterator; it.hasNext;) { //reparations为Collection
Reparation repa = (Reparation) it.next;
(repa.getId reparation.getId) {
it.remove;
flag = true;
;
}
}
(flag) {
this.reparations.add(reparation);
}
}

综上所述:我们在编程时候尤其是在对Iterator中数据进行对集合类中数据进行删除操作时候可以再Iterator中进行但是有关修改操作我们要换中方式在 Iterator中变相进行修改养成良好多线程变成习惯将代码危险防范于未然.
Tags:  javacollection ss501collection collection vb中遍历collection

延伸阅读

最新评论

发表评论