Open cccreator opened 6 years ago
public List getBusClusterData(String carNo, String[] routeIds, String orgName, Double xmax, Double xmin, Double ymax, Double ymin, Double rangeFactor, Boolean isConverge, Boolean isMoved, String directionName) {
Map<String, BusGpsMessage> busGPSDataCache;
busGPSDataCache = BusRealDataCacheService.getBusGPSDataCache();
Map<String, BusArrLeftMessage> busArrLeftDataCache;
busArrLeftDataCache = BusRealDataCacheService.getBusArrLevDataCache();
Map<String, List<Double>> routeAvgSpeed = new LinkedHashMap<String, List<Double>>();
Map<String, PassengerInformationMessage> passengerData = BusRealDataCacheService.getPassengerInformationCache(); //gisMonitorDao.getPassengerData();
Map<String, BusClusterData> busClusterDataMap = new ConcurrentHashMap<String, BusClusterData>(); //productID,busClusterData
List<BusClusterData> listClusterResult = new ArrayList<BusClusterData>();
Set<String> set = busGPSDataCache.keySet();
List<CompanyInfo> listUserCompany = UserUtils.getFZCompanyList();//用户拥有的组织权限
List<String> listUserOrgName = new ArrayList<>();
DecimalFormat dcmFmtLat = new DecimalFormat("#.000000");
for (int i = 0; i < listUserCompany.size(); i++) {
listUserOrgName.add(listUserCompany.get(i).getOrgName());
}
/*使用迭代器*/
Iterator itor = set.iterator();
Iterator itor_1 = set.iterator();
DecimalFormat dcmFmt = new DecimalFormat("#.0000");
String key;
String keyRoute;
Double aggRange = 0.0;
if (isConverge) {
aggRange = rangeFactor;
}
Set<String> routeSet = new HashSet<String>();
Integer routePassengers = new Integer(0);
//定义聚合的时间戳
Date dt = new Date();
List<String> orgIdList = gisMonitorDao.getSubOrg(orgName);
int max = 100;
int min = 0;
while (itor_1.hasNext()) {
keyRoute = (String) itor_1.next();
/*根据缓存中的key值,获取对应得实体类*/
BusGpsMessage busGpsMsg = busGPSDataCache.get(keyRoute);
if (!busGpsMsg.getRouteID().isEmpty() && !routeAvgSpeed.containsKey(busGpsMsg.getRouteID())) {
List<Double> list = new ArrayList<Double>();
list.add(busGpsMsg.getSpeed());
routeAvgSpeed.put(busGpsMsg.getRouteID(), list);
} else if (!busGpsMsg.getRouteID().isEmpty() && routeAvgSpeed.containsKey(busGpsMsg.getRouteID())) {
routeAvgSpeed.get(busGpsMsg.getRouteID()).add(busGpsMsg.getSpeed());
}
}
/*while循环,如果还有下一个数据就一直执行*/
while (itor.hasNext()) {
key = (String) itor.next();
/*根据缓存中的key值,获取对应得实体类*/
BusGpsMessage busGpsMsg = busGPSDataCache.get(key);
BusClusterData busClusterData = new BusClusterData();
if (StringUtil.isNotEmpty(busGpsMsg.getProductID())) {
/*
if (Constants.CITYNAME_FZ.equals(propertiesUtil.getCityName())) {
*/
//如果选择了总组织,那么判断用户所拥有的组织权限
if (orgName.equals("") || orgName.equals(propertiesUtil.getFullCityName())) {
if (busGpsMsg.getOrgName().equals("")) {
continue;
}
if (!listUserOrgName.contains(busGpsMsg.getOrgName())) {
continue;
}
} else {
if (!orgIdList.contains(busGpsMsg.getOrgId())) {
continue;
}
}
/*}*/
busClusterData.setRouteName(busGpsMsg.getRouteName());
busClusterData.setFuelType(busGpsMsg.getFuelType());
busClusterData.setBusGrade(busGpsMsg.getBusGrade());
/*将获取的实体类放入一个list集合中*/
busClusterData.setAngle(busGpsMsg.getAngle());
busClusterData.setAvgSpeed(busGpsMsg.getAvgSpeed());
busClusterData.setBusCardNo(busGpsMsg.getBusCardNo());
busClusterData.setBusCount(1);
//busClusterData.setCameraCodeArray(busGpsMsg.getCameraCodeArray());
busClusterData.setBusId(busGpsMsg.getBusId());
busClusterData.setHeight(busGpsMsg.getHeight());
//保留6位小数
busClusterData.setLatitude((double) Math.round(busGpsMsg.getLatitude() * 1000000) / 1000000);
busClusterData.setLongitude((double) Math.round(busGpsMsg.getLongitude() * 1000000) / 1000000);
busClusterData.setMileage(busGpsMsg.getMileage());
busClusterData.setOrgName(busGpsMsg.getOrgName());
busClusterData.setProductID(busGpsMsg.getProductID());
busClusterData.setRouteID(busGpsMsg.getRouteID());
busClusterData.setSubRouteID(busGpsMsg.getSubRouteID());
busClusterData.setSequenceType(busGpsMsg.getSequenceType());
busClusterData.setSpeed(new BigDecimal(busGpsMsg.getSpeed()).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
busClusterData.setActTime(busGpsMsg.getMsgTime());
busClusterData.setPassengers(busGpsMsg.getPassengers());
busClusterData.setParentOrgName(busGpsMsg.getParentOrgName());
busClusterData.setIsMoved(busGpsMsg.getMoved());
busClusterData.setClusterDate(DateUtil.datetime2Str(dt));
//设置单辆车的图标
String routeIcon = MapCacheManager.cacheMapRouteIcon.get(busGpsMsg.getRouteID());
busClusterData.setBusIcon(routeIcon == null ? "" : routeIcon.split(",")[0]);
if (routeAvgSpeed.get(busGpsMsg.getRouteID()) != null && routeAvgSpeed.get(busGpsMsg.getRouteID()).size() > 0) {
Double sum = 0.0;
for (int i = 0; i < routeAvgSpeed.get(busGpsMsg.getRouteID()).size(); i++) {
sum = routeAvgSpeed.get(busGpsMsg.getRouteID()).get(i) + sum;
}
busClusterData.setRouteAvgSpeed(Double.parseDouble(dcmFmt.format(sum / routeAvgSpeed.get(busGpsMsg.getRouteID()).size())));
} else {
busClusterData.setRouteAvgSpeed(0.0);
}
if (busArrLeftDataCache.containsKey(busGpsMsg.getProductID())) {
busClusterData.setStationTime(busArrLeftDataCache.get(busGpsMsg.getProductID()).getMsgTime());
}
if (busGpsMsg.getSequenceType() == 4) {
busClusterData.setDirectionName("上行");
} else if (busGpsMsg.getSequenceType() == 5) {
busClusterData.setDirectionName("下行");
} else if (busGpsMsg.getSequenceType() == 6) {
busClusterData.setDirectionName("环行");
}
try {
if (!"".equals(directionName)) {
if (directionName.equals(busClusterData.getDirectionName())) {
busClusterDataMap.put(busClusterData.getProductID(), busClusterData);
}
} else {
busClusterDataMap.put(busClusterData.getProductID(), busClusterData);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Set<String> setCluster = busClusterDataMap.keySet();
/*使用迭代器*/
Iterator itorCluster = setCluster.iterator();
String keyCluster;
List<BusClusterData> listCluster = new ArrayList<BusClusterData>();
/*while循环,如果还有下一个数据就一直执行*/
//得到listCluster值
while (itorCluster.hasNext()) {
BusClusterData busClusterData1;
keyCluster = (String) itorCluster.next();
/*根据缓存中的key值,获取对应得实体类*/
busClusterData1 = busClusterDataMap.get(keyCluster);
listCluster.add(busClusterData1);
}
//线路id不为空,不聚合车辆,只显示车辆选中线路的车辆
if (routeIds.length > 0) {
for (int i = 0; i < routeIds.length; i++) {
routeSet.add(routeIds[i]);
}
for (Map.Entry me : passengerData.entrySet()) {
PassengerInformationMessage pi = (PassengerInformationMessage) me.getValue();
if (routeSet.contains(pi.getRouteID())) {
routePassengers += pi.getTotalPassengerFlow();
}
}
for (int m = 0; m < listCluster.size(); m++) {
if (listCluster.get(m) != null && routeSet.contains(listCluster.get(m).getRouteID())) {
Double px0 = listCluster.get(m).getLongitude(); //经
Double py0 = listCluster.get(m).getLatitude(); //纬
//判断车辆地图内
if (px0 < xmax && px0 > xmin && py0 < ymax && py0 > ymin) {
listClusterResult.add(listCluster.get(m));
}
}
}
if (isMoved) {
for (int i = 0; i < listClusterResult.size(); i++) {
try {
BusClusterData busClusterData = listClusterResult.get(i);
if (busClusterData.getIsMoved() != null && !busClusterData.getIsMoved()) {
listClusterResult.remove(busClusterData);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
return listClusterResult;
}
//线路Id为空,聚合所有的车辆
List car = new ArrayList();
car.add(carNo);
//循环使每一辆车作为聚合焦点的车辆
for (int m = 0; m < listCluster.size(); m++) {
if (listCluster.get(m) != null) {
String carno1 = listCluster.get(m).getBusCardNo(); //车辆属性:车牌号
//如果该车不存在于已被聚合的车辆数组中
if (car.indexOf(carno1) == -1) {
Double lat = listCluster.get(m).getLongitude();
Double lon = listCluster.get(m).getLatitude();
//设置聚合范围
Double spxmin = lat - aggRange;
Double spxmax = lat + aggRange;
Double spymin = lon - aggRange;
Double spymax = lon + aggRange;
//车的数量默认是1,不存在同一个经纬度,存在两辆车的问题。因为车是根据图层上已经标好的车来算的,放到数组里。每个车都有唯一的下标。
int count = listCluster.get(m).getBusCount(); //车辆属性:车量数
//int passengers = listCluster.get(m).getPassengers(); //车辆属性:车量数
//遍历图层上所有车辆;
for (int n = 0; n < listCluster.size(); n++) {
if (listCluster.get(n) != null) {
String carno = listCluster.get(n).getBusCardNo(); //车辆属性:车牌号
int count1 = listCluster.get(n).getBusCount(); //车辆属性:数量
//int passengers1 = listCluster.get(n).getPassengers(); //车辆属性:数量
Double px0 = listCluster.get(n).getLongitude(); //经
Double py0 = listCluster.get(n).getLatitude(); //纬
//判断车辆是否在聚合范围内,不包含聚合焦点车辆,不包含视野外车辆
if (px0 < spxmax && px0 > spxmin && py0 < spymax && py0 > spymin && n != m &&
px0 < xmax && px0 > xmin && py0 < ymax && py0 > ymin) {
//如果聚合数组中不存在聚合范围内的车辆
if (car.indexOf(carno) == -1) {
count = count + count1; //范围内的车辆的数量相加
///passengers = passengers + passengers1; //范围内的车辆的数量相加
car.add(carno); //把聚合焦点车辆范围内的车辆放入聚合车辆数组中
listCluster.set(n, null); //设置聚合焦点车辆属性的数量值
}
}
}
}
listCluster.get(m).setBusCount(count); //设置聚合焦点车辆属性的数量值
if (count > 1) {
String routeIcon = MapCacheManager.cacheMapRouteIcon.get(listCluster.get(m).getRouteID());
listCluster.get(m).setBusIcon(routeIcon == null ? "" : routeIcon.split(",")[1]);
}
}
}
}
for (int l = 0; l < listCluster.size(); l++) {
if (listCluster.get(l) != null) {
listClusterResult.add(listCluster.get(l));
}
}
if (isMoved) {
for (int i = 0; i < listClusterResult.size(); i++) {
try {
BusClusterData busClusterData = listClusterResult.get(i);
if (busClusterData.getIsMoved() != null && !busClusterData.getIsMoved()) {
listClusterResult.remove(busClusterData);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
return listClusterResult;
}
聚合里面当routeid为空时,通过经纬度范围聚合所有车辆
List car = new ArrayList();
,car.indexOf(carno1)
当对象car中没有carno1
时,返回-1
,有则返回List
中的位置;listCluster.set(n, null);
将放进List中的车辆在listCluster
中的位置设置为null
;使用ConcurrentHashMap
多线程环境下,使用Hashmap
进行put
操作会引起死循环,导致CPU利用率接近100%。HashTable
容器使用synchronized
来保证线程安全,但在线程竞争激烈的情况下HashTabl
的效率会非常低下。因为当一个线程访问HashTable
的同步方法时候,其它线程访问HashTable
会进入阻塞或者轮训状态。所有访问HashTable
的线程都必须竞争同一把锁,竞争越激烈效率越低。
ConcurrentHashMap
使用了锁分段技术:将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其它线程访问。有些方法是需要跨段的,比如size()
和containsValue()
,它们可能需要锁定整个表而不是某个段,这就需要按顺序锁定所有段,又按顺序释放所有段,否则容易造成死锁。在ConcurrentHashMap
内部,段数组是final
的,成员变量实际也是final
的,但仅仅将数组声明为final
的并不保证数组成员也是final
的,这需要实现上的保证。这可以确保不会出现死锁,因为获得锁的顺序是固定的。
synchronized
关键字是用来修饰线程同步的,在多线程环境下,控制synchronized
代码段不被多个线程同时执行。synchronized
既可以修饰代码段,也可以修饰方法。synchronized
修饰的是括号里面的对象,而不是代码。对于非static
的synchronized
方法,锁的就是对象本身。当synchronized
锁住一个对象的时候,别的线程如果也要访问这个对象的锁,就必须等待这个线程执行完成释放锁。在使用synchronized
关键字的时候,能缩小代码段的范围就尽量缩小,能在代码段上加同步就不要在整个方法上加,这叫减小锁的粒度。
public static Map<String, BusGpsMessage> gpsDataCache = new ConcurrentHashMap<>();
// GPS数据
synchronized (gpsDataCache) {
if (MQRecv.BUSDATA_GPS == msgType) {
ProtoBufMsg.BusGpsMsg realData = null;
try {
realData = ProtoBufMsg.BusGpsMsg.parseFrom(realMsg);
} catch (Exception e) {
logger.error("处理mq信息出现出现异常,出现问题模块GPS数据:msgType=" + msgType + ";车载机id=" + productID + ";异常信息=" + e.getMessage());
logger.error("报错代码为:ProtoBufMsg.BusGpsMsg realData = ProtoBufMsg.BusGpsMsg.parseFrom(realMsg);以下为异常堆栈信息:");
logger.error("hisense exception stack:", e);
return;
}
BusGpsMessage busMsg = new BusGpsMessage();
productID = realData.getProductID();
String msgTime = realData.getMsgTime();
BusGpsMessage busMsgLst = gpsDataCache.get(productID);
if (msgTime != null) {
LocalDateTime localDateTime = TimeUtil.parseTime(msgTime);
if (busMsgLst != null) {
String msgTimeLst = busMsgLst.getMsgTime();
if (msgTimeLst != null) {
LocalDateTime localDateTimeLst = TimeUtil.parseTime(msgTimeLst);
//如果上一条数据的GPS上报时间比当前数据的GPS上报时间大,则不更新缓存
if (localDateTimeLst.isAfter(localDateTime)) return;
}
}
} else {
return;
}
// 获取通用实时数据项并将其封装到busMsg中
commonData.put("msgTime", realData.getMsgTime());
commonData.put("productID", realData.getProductID());
commonData.put("routeID", realData.getRouteID());
if(cityName.equals("SZ")||cityName.equals("QD")){
double[] dou = GpsUtil.toGCJ02Point( realData.getLatitude(),realData.getLongitude());
double lon = dou[1];
double lat = dou[0];
commonData.put("longitude", lon);
commonData.put("latitude", lat);
}
else{
commonData.put("longitude", realData.getLongitude());
commonData.put("latitude", realData.getLatitude());
}
/*commonData.put("longitude", realData.getLongitude());
commonData.put("latitude", realData.getLatitude());*/
commonData.put("subRouteID", realData.getSubRouteID());
commonData.put("sequenceType", realData.getSequenceType());
commonData.put("isReissue", realData.getIsReissue());
commonData.put("height", realData.getHeight());
commonData.put("speed", realData.getSpeed());
commonData.put("angle", realData.getAngle());
commonData.put("mileage", realData.getMileage());
setCommonMessage(busMsg, commonData);
/*获取Bus其它GPS实时数据项,并将其封装到busMsg中
如果传上来的实时数据为空,再根据routeId或者productId从基础信息的缓存中查询*/
Integer sequenceTypeFlag = realData.getSequenceTypeFlag();
if (sequenceTypeFlag != null) {
busMsg.setSequenceTypeFlag(sequenceTypeFlag);
}
String stationGlobalID = realData.getStationGlobalID();
if (StringUtil.isNotEmpty(stationGlobalID)) {
busMsg.setStationGlobalID(stationGlobalID);
}
Integer timeType = realData.getTimeType();
if (timeType != null) {
busMsg.setTimeType(timeType);
}
Double avgSpeed = realData.getAvgSpeed();
if (avgSpeed != null) {
busMsg.setAvgSpeed(avgSpeed);
}
if (MapCacheManager.getCacheMapCardIdByProductId(busMsg.getProductID()) != null && MapCacheManager.getCacheMapCardIdByProductId(busMsg.getProductID()).getIsPassenDev().equals("1")) {
if (BusRealDataCacheService.getPassengerInformationCache().containsKey(busMsg.getProductID())) {
int passengerFlow = BusRealDataCacheService.getPassengerInformationCache().get(busMsg.getProductID()).getTotalPassengerFlow();
/*if (passengerFlow >= 0) {
logger.info("客流数据>=0的车辆,所属组织==" + busClusterData.getOrgName() + ";车牌号为==" + busClusterData.getBusCardNo() + ";客流数==" + passengerFlow);
}*/
busMsg.setPassengers(passengerFlow);
if (null != busMsg.getSeatCount() && null != busMsg.getStandCount()
&& !"".equals(busMsg.getSeatCount()) && !"".equals(busMsg.getStandCount()
) && busMsg.getSeatCount() > 0 && busMsg.getStandCount() > 0) {
busMsg.setBusLoadRadio(Double.parseDouble(String.format("%.2f", (Double.parseDouble(String.valueOf(passengerFlow)) / (busMsg.getSeatCount() + busMsg.getStandCount()))).toString()));
}
} else {
//有设备,无客流
busMsg.setPassengers(-1);
}
} else {
//无设备
busMsg.setPassengers(-2);
}
//判断车辆经纬度是否变动,如果不变动,则将相应字段值设置为false
judgeIsMoved(gpsDataCache.get(busMsg.getProductID()), busMsg);
// 将整合后的数据放入缓存
gpsDataCache.put(productID, busMsg);
}
}
} catch (Exception e) {
logger.error("处理mq信息出现出现异常,出现问题模块GPS数据;异常信息=" + e.getMessage());
logger.error("hisense exception stack:", e);
}
缓存取数据