![](/img/trans.png)
[英]Getting NullPointerException whit JasperReports into a Multi-Thread application
[英]Getting NullPointerException in multi thread environment in spite of null check
我有一個名為statisticsCache
的全局緩存,該緩存正在被多個線程同時修改和讀取。 即使在我應用了空檢查之后,但有時它會在加載運行中引發NullPointerException
。 詳情請見下文:
static Map<String, List<Statistics>> statisticsCache = new ConcurrentHashMap<String, List<Statistics>>();
// method to read the global cache
List<Statistics> getStatisticsForQueue(String name) {
List<Statistics> statsCopy = Collections.emptyList();
List<Statistics> statistics = statisticsCache.get(name);
if (statistics != null && !statistics.contains(null)) //Here is the check to avoid NPE but sometimes does not works
statsCopy = new ArrayList<Statistics>(statistics);
return statsCopy;
}
//method to write into global cache
private void setStatisticsListForQueue(String name) {
// flushing all pending Last writes of buckets of a queue to DB
flushStatisticToDB(name);
if (!statisticsCache.containsKey(name)) {
statisticsCache.put(name, new ArrayList<Statistics>(1));
}
List<Statistics> queueStatisticsList = queueServiceMetaDao
.findStatisticsByname(name);
if (queueStatisticsList != null && !queueStatisticsList.isEmpty()) {
for (Statistics statistic : queueStatisticsList) {
// to avoid NPE
if (statisticsCache.get(name).contains(statistic)) {
statisticsCache.get(name).remove(statistic);
}
statisticsCache.get(name).add(statistic);
}
} else {
statisticsCache.put(name, new ArrayList<Statistics>(1));
}
}
//method where I am getting NPE
public long getSize(String name) {
long size = 0L;
List<Statistics> statistics = getStatisticsForQueue(name);
for (Statistics statistic : statistics) {
size += statistic.getSize(); //Sometimes it throws NullPointerException
}
return size;
}
我應該采取什么預防性檢查來避免這種情況?
即使在我應用了空檢查之后,但有時它會在加載運行中引發
NullPointerException
。
好的,因此,如果您有多個線程執行此代碼,則(IMO)最可能的解釋是代碼未正確同步。 當然,該映射本身是ConcurrentHashMap,因此應該是線程安全的。 但是,您有多個線程創建,訪問和修改ArrayLists
而列表上沒有任何互斥或其他同步。
有很多事情可能出錯。 一種可能性是,一個線程從列表中刪除一個元素,而第二個線程同時在同一列表上調用getSize()
。 一個可能的結果是, getSize()
中的迭代將看到列表大小的陳舊值,並返回一個已被另一個線程移除而為空的數組元素。 由於列表上兩個線程的操作沒有同步,因此,關於一個線程的列表更改對另一個線程的可見性,“所有賭注都已關閉”。
不管采用哪種確切的機制導致NPE,您在此處所做的操作都不能滿足必須保證滿足可預測行為的JLS要求(請參閱JLS 17.4 )。
我應該采取什么預防性檢查來避免這種情況?
您無法通過這種方式解決問題。 您需要在列表上進行正確的同步,以確保讀取和更新不會重疊。 您還需要使用putIfAbsent
而不是if (! containsKey) { put ... }
處理另一個競爭條件。
我認為statistic.getSize()可能為null,因此您嘗試這樣做:
size += statistic.getSize();
拋出NullPointerException
您應該檢查所有Statistics對象是否都具有其屬性“ size”!= null
問題實際上不是getSize()
方法,因為long不能為null。 實際的NPE是這個
List<Statistics> statistics = getStatisticsForQueue(name);
for (Statistics statistic : statistics)
如果statistics為null
則for循環將具有NPE。 因此,您可以避免發生的事情是
if(statistics != null)
for (Statistics statistic : statistics)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.