Ofbiz2.1有兩個bug,都涉及到線程安全性,小并發(fā)的時候不容易發(fā)現(xiàn),大并發(fā)下有時候會出現(xiàn),并發(fā)數(shù)越高出現(xiàn)的頻度就比較高,尤其對于實體引擎的那個bug,在系統(tǒng)初始化的時候如果遭遇大并發(fā),會有一定頻度的出現(xiàn)。
1。entity engine的ModelEntity.getField方法存在線程安全隱患,會造成 XXXX is not a field of XXX的異常,以下是原有代碼片斷:
public ModelField getField(String fieldName) {
if (fieldName == null) return null;
if (fieldsMap == null) {
fieldsMap = new HashMap(fields.size());
for (int i = 0; i < fields.size(); i++) {
ModelField field = (ModelField) fields.get(i);
fieldsMap.put(field.name, field);
}
return (ModelField) fieldsMap.get(fieldName);
}
由于getField方法沒有同步(會造成性能下降),因此紅色標(biāo)標(biāo)注的那段代碼存在線程安全問題,必須進(jìn)行同步。在大并發(fā)下如果多個調(diào)用這個方法,最先調(diào)用的線程沒有執(zhí)行完循環(huán)的情況下,后續(xù)的線程通過最后的語句return的時候得到的就是Null(fieldsMap已經(jīng)被第一個線程賦值了,后續(xù)線程不會進(jìn)入紅色標(biāo)準(zhǔn)的代碼區(qū)域)。
修改后的代碼如下:
public ModelField getField(String fieldName) {
if (fieldName == null) return null;
if (fieldsMap == null) {
createFields();
}
return (ModelField) fieldsMap.get(fieldName);
}
public synchronized void createFields()
{
fieldsMap = new HashMap(fields.size());
for (int i = 0; i < fields.size(); i++) {
ModelField field = (ModelField) fields.get(i);
fieldsMap.put(field.name, field);
}
}
這個Bug在3.0中已經(jīng)被修正。
2。UtilCache.get方法同樣存在線程安全隱患,會造成LinkedList.remove或者LinedList.addFirst的空值針異常,不注意還會以為是LinkedList的bug。以下是原代碼片斷:
public Object get(Object key) {
if (key == null) {
missCount++;
return null;
}
UtilCache.CacheLine line = (UtilCache.CacheLine) cacheLineTable.get(key);
if (hasExpired(line)) {
// note that print.info in debug.properties cannot be checked through UtilProperties here, it would cause infinite recursion
// if (Debug.infoOn()) Debug.logInfo("Element has expired with key " + key);
remove(key);
line = null;
}
if (line == null) {
// if (Debug.infoOn()) Debug.logInfo("Element not found with key " + key);
missCount++;
return null;
}
// if (Debug.infoOn()) Debug.logInfo("Element found with key " + key);
hitCount++;
if (maxSize > 0) {
keyLRUList.remove(key);
keyLRUList.addFirst(key);
}
return line.getValue();
}
紅色標(biāo)準(zhǔn)的部分是有問題的代碼,修改后的代碼如下:
public Object get(Object key) {
if (key == null) {
missCount++;
return null;
}
UtilCache.CacheLine line = (UtilCache.CacheLine) cacheLineTable.get(key);
if (hasExpired(line)) {
// note that print.info in debug.properties cannot be checked through UtilProperties here, it would cause infinite recursion
// if (Debug.infoOn()) Debug.logInfo("Element has expired with key " + key);
remove(key);
line = null;
}
if (line == null) {
// if (Debug.infoOn()) Debug.logInfo("Element not found with key " + key);
missCount++;
return null;
}
// if (Debug.infoOn()) Debug.logInfo("Element found with key " + key);
hitCount++;
if (maxSize > 0) {
synchronized ( this)
{
keyLRUList.remove(key);
keyLRUList.addFirst(key);
}
}
return line.getValue();
}
這個BUG在3.0種也修正了。