碰到一个统计门店及周边用户人数的需求。想都没想直接查询要统计的门店,循环统计每个门店用户的人数,但是用户太多一个个计算用户是否在门店周边很费时大概一次请求到返回数据要一分钟,这肯定要炸了,然后想到开通多线程去统计门店周边人数,有点像多线程求和 的样子。废话不多说了,直接上代码。
控制类方法
service 层:
ThreadUtil工具类
/**
* 多线程求和
* @author Administrator
*
*/
@Component
public class ThreadUtil {
private static Logger logger =Logger.getLogger(ThreadUtil.class);
@Autowired
private RedisTemplate<String, String> redisTemplate;
public int sum(final List<String> array,final Double minlat,final Double maxlat,final Double minlng,final Double maxlng ) {
if (array == null || array.size() == 0) {
throw new IllegalArgumentException("array length must greater than 0");
}
// 保存线程相关数据
final RuntimeData rd = new RuntimeData();
// 线程数
int threadCount = rd.getThreadCount(array);
System.out.println("thread count:" + threadCount);
//每线程计算的数组元素个数
final int lenPerThread = array.size() / threadCount;
// System.out.println(lenPerThread);
for (int i = 0; i < threadCount; i++) {
final int index = i;
new Thread() {
@Override
public void run() {
int s = 0;
int start = index * lenPerThread-1; // 开始数
int end = start + lenPerThread-1; // 结束元素
for (int j = start; j < end; j++) {
String str= redisTemplate.opsForValue().get(array.get(index));
net.sf.json.JSONObject sfObject = net.sf.json.JSONObject.fromObject(str);
//mrp.setMobileId(sfObject.getString("mobileId"));
//mrp.setMobileNo(sfObject.getString("mobileNo"));
Double lat=Double.parseDouble(sfObject.getString("latitude"));
Double lng=Double.parseDouble(sfObject.getString("longitude"));
if(lat>minlat && lat<maxlat && lng>minlng && lng<maxlng) {
s++;
}
}
synchronized (rd) {
rd.sum += s;
rd.finishThreadCount++;
// System.out.println("thread[" + getName() + "] finished,sum:" + d.sum);
}
};
}.start();
}
//余下的array元素
int remain = array.size() % threadCount;
System.out.println("remain element count:" + remain);
long s = 0;
for (int i = array.size() - remain; i < array.size(); i++) {
logger.info("array.get(i-1):"+array.get(i-1));
String str= redisTemplate.opsForValue().get(array.get(i-1));
net.sf.json.JSONObject sfObject = net.sf.json.JSONObject.fromObject(str);
Double lat=Double.parseDouble(sfObject.getString("latitude"));
Double lng=Double.parseDouble(sfObject.getString("longitude"));
if(lat>minlat && lat<maxlat && lng>minlng && lng<maxlng) {
s++;
}
}
synchronized (rd) {
rd.sum += s;
}
while (rd.finishThreadCount != threadCount) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
return rd.sum;
}
}
/**
* 保存运行时的相关数据
*
*/
class RuntimeData {
//保存和
int sum;
//默认线程数
int defThreadCount = 17;
//已经执行完成的线程数
int finishThreadCount;
/**
* 根据数据长度获取线程数,线程数不会大于数组的长度。
* @param array
* @return
*/
public int getThreadCount(List<String> array) {
if (array.size() < defThreadCount) {
return array.size();
}
return defThreadCount;
}
}
结果: