业务:快速处理大量数据,保证数据安全的情况下,提高数据处理速度
技术: 使用ConcurrentHashMap和ThreadPoolExecutor、CountDownLatch实现多线程
一、按数据量创建对应数目的线程
public void userThreadPool(String[] infor, Ggtable gg,
Map<String, Map<String, List<ClickCountShow>>> result,
Map<String, List<ClickCountShow>> value, String modelname)
throws InterruptedException {
// 每个线程处理的数组大小
int threadSize = 5;
int dataSize = infor.length;
int RunnNum = dataSize / threadSize + 1;
ThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(RunnNum);
CountDownLatch countdownlatch = new CountDownLatch(RunnNum);
String[] newinfor = null;
for (int i = 0; i < RunnNum; i++) {
if ((i + 1) == RunnNum) {
newinfor = Arrays.copyOfRange(infor, threadSize * i, dataSize);
} else {
newinfor = Arrays.copyOfRange(infor, i * threadSize, threadSize
* (i + 1));
}
ExecutorSt stRunnable = new ExecutorSt(newinfor, countdownlatch,
gg, result, value, modelname);
executor.execute(stRunnable);
}
countdownlatch.await();
executor.shutdown();
}
次级业务类将数据分类存储到ConcurrentHashMap中:
public class ExecutorSt implements Runnable {
boolean flag = true;
private CountDownLatch countdownlatch;
private String[] infor;
private Map<String, Map<String, List<ClickCountShow>>> result;
private Map<String, List<ClickCountShow>> value = null;
private Ggtable gg;
private String modelname;
public ExecutorSt(String[] infor, CountDownLatch countdownlatch,
Ggtable gg,
Map<String, Map<String, List<ClickCountShow>>> result,
Map<String, List<ClickCountShow>> value, String modelname) {
this.infor = infor;
this.countdownlatch = countdownlatch;
this.gg = gg;
this.result = result;
this.modelname = modelname;
this.value = value;
}
@Override
public void run() {
if (infor != null && infor.length > 0) {
delinfor();
}
countdownlatch.countDown();
}
public void delinfor() {
for (String str : infor) {
// 赋值userid@时间@ip@MacAddress
String[] info = str.split("@");
GetOrgInfor gi=new GetOrgInfor(Integer.valueOf(info[0]));
FutureTask<Object[]>obj=new FutureTask<>(gi);
new Thread(obj).start();
if (obj != null) {
try {
Object[] rs=obj.get();
String key =(String) rs[1];
String key2 =(String) rs[0];
ClickCountShow ccs = new ClickCountShow(
modelname, gg.getGgtitle(),
new Integer(info[0]), key2, key,
info[1], info[2], info[3]);
List<ClickCountShow> listccs = null;
// 存放组织名对应的map
if (result.containsKey(key) == false) {
// 创建新的map存储map<username,list>
value = new ConcurrentHashMap<String, List<ClickCountShow>>();
listccs = new ArrayList<>();
listccs.add(ccs);
value.put(key2, listccs);
result.put(key, value);
} else {
value = result.get(key);
if (value.containsKey(key2) == false) {
// 不存在则新增数据
listccs = new ArrayList<>();
listccs.add(ccs);
value.put(key2, listccs);
} else {
listccs = value.get(key2);
listccs.add(ccs);
}
}
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
//e.printStackTrace();
System.out.println("数据存在错误!");
}
}
}
}
}
次级线程中创建新的Callable类型的GetOrgInfor线程来实现查询,避免查询逻辑导致当前线程停止,主线程阻塞
public class GetOrgfInfor implements Callable<Object[]>{
private Integer userid;
public GetOrgfInfor(Integer userid){
this.userid=userid;
}
@Override
public Object[] call() throws Exception {
return iuserinfoservice.getOrgnameByUserId(Integer.valueOf(userid));
}
}
主线程声明result等对象,并调用线程池创建次级线程
public String getInfo() {
ClickCount cc = iclickcountservice.getClickCountByGgtableId(ggtableId);
// 创建存储的map集合
// <orgname,map<username,List>>
Map<String, Map<String, List<ClickCountShow>>> result = new ConcurrentHashMap<>();
Map<String, List<ClickCountShow>> value = null;
ModelBasic model = imodelbasicservice.getTypeById(cc.getModelid());
Ggtable gg = itongyongservice.findByID(ggtableId);
String modelname = model.getModelname();
if (cc.getUsercount() != null) {
String[] allclick = cc.getUsercount().split("#");
try {
userThreadPool(allclick, gg, result, value, modelname);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
request.setAttribute("result", result);
return "singleclickshow";
}
其他:
问题:ssh框架应用多线程,若当前逻辑需要创建新线程去后台查询,且该查询则其他重复查询单线程对后台请求如果该请求为runnable无返回,则当前线程直接停止,线程跳转停止进入。主线程中的次级线程会因为次级线程内包含的runnable查询类型方法的执行而终止当前代码块,导致同步锁无法释放,主线程进入阻塞态。
解决办法:使用合并查询来减少次级线程中包含的runnable类型查询,且将查询方法包含在新的CallAable线程中,从result中获取查询的内容,用于次级线程处理合并concurrentHashMap