参考各类blog
【 不正确使用HashMap,造成CPU 100%的问题】和一些关于多线程的技术文档【 浅谈Java多线程的同步问题】。
分析了一下.
先列出问题的代码:
public class DataManager {
......
private Map<Object, Integer> fStyleCache = new HashMap<Object, Integer>();
private Map<Object, Integer> fSkuCache = new HashMap<Object, Integer>();
......
public static void initialize() {
WorkerQueue q = new WorkerQueue();
..........
q.add(new DBWorker() {
@Override
protected void process()
throws Exception
{
DataManager dm = getInstance(this);
dm.getBaseSscDataUnit(dm.getBasePOSStartEndMonth(), this);
}
});
q.add(new DBWorker() {
@Override
protected void process()
throws Exception
{
DataManager dm = getInstance(this);
dm.getBaseSscDcDataUnit(dm.getBasePOSStartEndMonth(), this);
}
});
/*q.add(new DBWorker() {
@Override
protected void process()
throws Exception
{
DataManager dm = getInstance(this);
dm.getBaseProdAttrDataUnit(this);
}
});
*/
q.start();
}
..........
private StyleSkuCountDataUnit getBaseSscDataUnit(int[] posStartEndMonth, DBConnection dc)
throws SQLException
{
synchronized(fSscDataUnit) {
if(fSscDataUnit.IsNeedRetrieveDBAgain()) {
fSscDataUnit = this.buildSscDataUnit(......);//此方法调用getStyleSkuFromCache
fSscDataUnit.setIsNeedRetrieveDBAgain(false);
}
}
return fSscDataUnit;
}
private StyleSkuCountDataUnit getBaseSscDcDataUnit(int[] posStartEndMonth, DBConnection dc)
throws SQLException
{
synchronized(fSscDcDataUnit) {
if(fSscDcDataUnit.IsNeedRetrieveDBAgain()) {
fSscDcDataUnit = this.buildSscDcDataUnit(.......);//此方法调用getStyleSkuFromCache
fSscDcDataUnit.setIsNeedRetrieveDBAgain(false);
}
}
return fSscDcDataUnit;
}
private Integer getStyleSkuFromCache(Object styleSku, boolean isStyle){
Map<Object, Integer> cache = null;
if(isStyle){
cache = fStyleCache; //HashMap
}else{
cache = fSkuCache; //HashMap
}
Integer value = cache.get(styleSku);
if(null == value){
value = cache.size();
cache.put(styleSku, value);
}
return value;
}
}
每一次调用getStyleSkuFromCache 的时候,会向cache的map中put value. 而从HashMap内部实现来看 源码如下:
void
transfer(Entry[] newTable) {
Entry[] src = table;
int
newCapacity = newTable.length;
for
(
int
j =
0
; j < src.length; j++) {
Entry<K,V> e = src[j];
if
(e !=
null
) {
src[j] =
null
;
do
{
Entry<K,V> next = e.next;
int
i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
while
(e !=
null
);
}
}
}
从上面的代码看来,每一个线程进来都先执行. 一开始 fStyleCache ,fSkuCache 是空的,两个线程在执行上面的do{} 操作 同一个cache的map
,校验 while (e != null) 时 出现同步问题 ,
e.next读的是对方线程刚put的value 这样
e.next
一直不为null,
while一直被执行,变成了死循环。cpu就瞬间飙升到100%.总之,就是多线程操作(主要是修改map结构)同一个map导致内部map数据结构紊乱。
解决办法:
1.将HashMap改为ConcurrentHashMap,线程安全的Map。
2.对此方法 getStyleSkuFromCache(Object styleSku, boolean isStyle) 进行同步控制,单线程执行此方法。