Open cccreator opened 6 years ago
HashMap,非同步的,只允许一条记录的key值为空;HashMap是线程不安全的,为什么呢?这是由于hash碰撞与扩容导致的:比如当两个线程同时对HashMap进行put操作,key值为a1和a2,这个时候需要解决碰撞冲突,如果这个时候两个线程同时取到了对应位置头结点e1,则a1和a2必有一个丢失。当两个线程同时进行put操作时,HashMap存在扩容情况,同时调用resize()方法,各自生成新的数组并rehash后付给该map的底层数组table,结果最终只有一个线程生成的新的数组被赋给table变量。
TreeMap,能够把它保存的记录根据key排序,默认升序,也可以指定排序的指定容器,当用Iterator遍历TreeMap时,得到的记录是排过序的。TreeMap不允许key为null。是非同步的
Hashtable,与HashMap类似,不同点:key和value不允许为null;它支持线程的同步,即任一时刻只允许一个线程能写Hashtable,因此Hashtable在写入的时候比较慢。
保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的,在遍历的时候会比HashMap慢。key和value均允许为空,非同步的。
clear();从Map中删除所有映射;
remove(Object key);从Map中删除键和关联的值;
putAll(Map t);将制定Map中的所有映射复制到此map;
entrySet();返回Map中所包含映射的所有Set视图。Set中的每个元素都是一个Map.Entry对象,可以使用getKey()和getValue()方法(还有一个setValue()方法)访问Map.Entry对象的键元素和值元素;
values();返回map中所办函的Collection视图。删除Collection中的元素,还将删除Map中相应的映射(key和value);
containsKey(Object key);如果Map中包含指定键的映射,则返回true
containsValue(Object value);如果此Map将一个或多个键映射到指定值,则返回true
isEmptry();如果Map不包含键-值映射,则返回true
使用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);
}
Collection
Collection<E>
接口是所有单列集合的共同父接口,下面是常用的子类集合及其继承关系;Collection包括List和Set; 其中,
ArrayList是线程不安全的,底层使用数组实现,具有查询快,增删慢,效率高的特点,效率高;对于随机访问get和set,ArrayList优于LinkedList,因为LinkList要移动指针。
LinkedList是线程不安全的,底层是用链表实现的,具有查询慢,增删快的特点,效率高;对于新增和删除操作add和remove,LinkList要优于ArrayList,因为ArrayList要移动数据:当arrayList插入或者删除数据时,后面的数据会移动。
Vector是线程安全的,底层使用数组实现,具有查询快,增删慢的特点,效率低;
HashSet的底层是由HashMap来实现的,是通过对象的HashCode方法与equal方法来保证插入数据的唯一性;
TreeSet基于TreeMap的NavigableSet实现;