Hi,
We are building a tool for detecting non atomic usages of concurrent
collections.
We analyzed your code using our tool and found the following behavior:
Function addColumn at class SuperColumn tries to atomically add a column to
the concurrent collection “columns_” using the following code:
IColumn oldColumn = columns_.putIfAbsent(name, column);
if (oldColumn != null)
{
IColumn reconciledColumn = reconciler.reconcile((Column)column,
(Column)oldColumn);
while (!columns_.replace(name, oldColumn, reconciledColumn)) {
oldColumn = columns_.get(name);
reconciledColumn = reconciler.reconcile((Column)column, (Column)oldColumn);
}
}
This code can throw NullPointerException at function reconcile if there is a
columns_.remove(…) operation on the same key, by a different thread, between
the previous executed “columns_.replace(…)” and “columns_.get(…)”
operations.
Could you please let me know whether you consider this as a bug?
Another very similar scenario can occur at function “addColumn” of class
“ColumnFamily” where the program can throw NullPointerException while
checking the while loop condition.
A possible way of modifying the code for atomically adding a column to
“columns_” can be as follows:
for (;;) {
IColumn oldColumn = columns_.get(name);
if (oldColumn == null) {
if (columns_.putIfAbsent(name, column) == null)
return;
} else {
IColumn reconciledColumn = reconciler.reconcile((Column)column,
(Column)oldColumn);
if (columns_.replace(name, oldColumn, reconciledColumn))
return;
}
}
Thanks,
Ohad