一、报错问题解决
public String services(){
List <Future<Map<String,Object>>> list=new ArrayList<Future<Map<String,Object>>>();
int total=0;
//1.准备需要传递的参数
String condition = dealContent();
List<CompanyEntity> companyList = companyService.list(condition, -1, -1);
List<Node> nodeList = new ArrayList<Node>();
int nodeId = getNodeId();
if(nodeId != 0){
Node node = nodeService.getById(nodeId);
nodeList.add(node);
}else{
nodeList = nodeService.getAll();
}
List<JSONObject> comList = new ArrayList<JSONObject>();
for(CompanyEntity company : companyList){
for(Node node : nodeList){
JSONObject jsonObj = new JSONObject();
jsonObj.put("companyName", company.getCompanyName());
jsonObj.put("companyId", company.getCompanyId());
jsonObj.put("companyType", company.getType());
jsonObj.put("nodeName",node.getNode_name());
jsonObj.put("nodeId",node.getNode_id());
jsonObj.put("nodeIp", node.getNode_ip());
comList.add(jsonObj);
}
}
//2.数据分页处理
int pagesize=Integer.parseInt(super.getPagesize());
int nopage=Integer.parseInt(super.getNowpage());
int ThrearNum=0;
if(pagesize>ThreadUtil.CORE_POOL_SIZE){
ThrearNum=ThreadUtil.CORE_POOL_SIZE;
}else{
ThrearNum=pagesize;
}
try {
//计算数据总量:
int sumDataCount=comList.size();
List<JSONObject> dataList=new ArrayList<JSONObject>();
final CountDownLatch latch = new CountDownLatch(ThrearNum);
boolean flag=false;
int dataEnd=0;
int addData=0;
int j=1;
for (int i = 0; i < ThrearNum; i++) {
List<JSONObject> addList=new ArrayList<JSONObject>();
List<JSONObject> tempList=new ArrayList<JSONObject>(comList.size());
tempList=comList;
List<JSONObject> dealList=new ArrayList<JSONObject>();
if(sumDataCount%ThrearNum!=0){
addData=sumDataCount%ThrearNum;
flag=true;
}
//计算每个线程要处理的数据总量:
int dataCountPerThread=sumDataCount/ThrearNum;
//计算当前线程数据处理的起始索引:
int dataStart=i*dataCountPerThread;
//计算当前线程数据处理的结束索引:
dataEnd=(i+1)*dataCountPerThread;
//截取List,作为当前线程所需要处理的全部数据:
if(flag){
if(j<=addData){
//多余的数据,从最后的索引开始平均分配
addList.add(tempList.get(tempList.size()-j));
j++;
}
dealList=subData(tempList,dataStart, dataEnd);
if(addList.size()!=0){
dealList.add(addList.get(0));
addList.remove(0);
}
}else{
dealList=subData(tempList,dataStart, dataEnd);
//如果这里不使用subData,而是使用subList,则会报错:java.util.ConcurrentModificationException
//dealList=comList.subList(dataStart, dataEnd);
}
Callable<Map<String,Object>> c1 = new CallableCountThread(condition,dealList,VpcFlag,slbFlag,blockFlag,vpnFlag,latch);
Future<Map<String,Object>> f1=pool.submit(c1);
list.add(f1);
}
latch.await();
for(int i=0;i<list.size();i++){
Future<Map<String,Object>> f1=list.get(i);
total+=(Integer)f1.get().get("count");
if(null!=f1.get().get("data")){
dataList.addAll((List<JSONObject>)f1.get().get("data"));
}
}
doPage_special(total);
//3.查询分页开始和结束的索引位
int nowpage2 = (Integer) dataMap.get("nowpage");
int pagesize2 = (Integer) dataMap.get("pagesize");
List<JSONObject> showData=new ArrayList<JSONObject>();
if(dataList.size()==0){
}else{
if(nopage==1){
if(dataList.size()<=pagesize2){
showData=dataList.subList(0,dataList.size()-1);
showData.add(dataList.get(dataList.size()-1));
}else{
showData=dataList.subList(0,pagesize2);
}
}else{
if(dataList.size()<=(nopage)*pagesize2){
showData=dataList.subList((nopage-1)*pagesize2,dataList.size()-1);
showData.add(dataList.get(dataList.size()-1));
}else{
showData=dataList.subList((nopage-1)*pagesize2,nopage*pagesize2);
}
}
}
generateSuccessListResponse(showData);
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return JSON;
}
在使用Callablejiek接口实现多线程查询的时候,当时自己采用了subList方法去截取list,传递给xian线程处理。
后续,在查询的过程中,报出了ConcurrentModificationException错误,查资料之后发现,这个错误的核心问题,是由于在duoc多线程环境下,多个线程同时访问or修改同一个对象导致的。
百思不得其解。后续,将subListdang方法换成了subData,问题解决:
public List<JSONObject> subData( List<JSONObject> list,int start,int end){
List<JSONObject> dataList=new ArrayList();
for(int i=start;i<end;i++){
dataList.add(list.get(i));
}
return dataList;
}
二、报错原因分析:
究其原因,是因为subList被截取之后,返回的还是原来的list的引用。
大家可以看下面这个小例子:
package com.test.test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.json.JSONObject;
public class SubListTest {
public static List subData(List list,int start,int end){
List dataList=new ArrayList();
for(int i=start;i<end;i++){
dataList.add(list.get(i));
}
return dataList;
}
public static void main(String[] args) {
//示例一:
System.out.println("示例一:");
List list=new ArrayList();
for(int i =1;i<10;i++){
list.add(i);
}
List list2=new ArrayList();
System.out.println("list="+list);
list2=list.subList(2, 3);
System.out.println("list2="+list2);
list2.remove(0);
System.out.println("list="+list);
//示例二:
System.out.println("示例二:");
List list3=new ArrayList();
list3.add(0);
list3.add(1);
list3.add(2);
list3.add(3);
list3.add(4);
System.out.println("list3="+list3);
List list4=new ArrayList();
list4=subData(list3, 0, 2);
System.out.println("list4="+list4);
list4.remove(0);
list4.remove(0);
System.out.println("list4="+list4);
System.out.println("list3="+list3);
}
}
输出结果:
可以看到,示例一中,list2是由list调用subList之后返回的。但是,对于List2进行删除之后,原本的list的数据3也没了。
而,调用示例二中的自定义方法subData之后,list4的删除,并不会对于list3的数据有任何改变。
所以,这就解释了,为什么之前在调用subList方法的时候,多线程环境下会报出ConcurrentModificationException的原因:
因为subList截取之后,返回的还是原来那个对象的引用。你多个线程调用的时候,实际上还是操作的是之前的同一个引用,suoy所以肯定会报出ConcurrentModificationException的错误了!