Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LongAdder: How can the try block fail?

Tags:

I'm analyzing the LongAdder algorithm in detail. LongAdder extends the class Striped64 and in that class the essential method is retryUpdate. The following piece of code is taken from this method; in the linked source code it occupies lines 212–222:

try {  // Recheck under lock
  Cell[] rs; int m, j;
  if ( (rs = cells) != null &&
       (m = rs.length) > 0  &&
       rs[j = (m - 1) & h] == null) {
     rs[j] = r;
     created = true;
   }
} finally {
  busy = 0;
}

Question: How can this try block fail?

Note that the array access

rs[j = (m - 1) & h] 

shouldn't throw an IndexOutOfBoundsException because the result of a bitwise-and operation is always less than or equal than the minimum of its integer arguments, hence 0 <= j <= m-1 is within the bounds of the array.

like image 898
user120513 Avatar asked Nov 07 '18 18:11

user120513


2 Answers

This very much looks like the pattern used with ReentrantLock everywhere else in the jdk code itself. The "pattern" here is that you should always release the lock, even if an Exception occurred, so usually the code is written as:

Lock someLock...

try {
    // use someLock
} finally {
    someLock.unlock();
}

Since cellsBusy(it was renamed from busy) is actually a busy-spin lock, the pattern is sort of the same here. As such:

cellsBusy = 0;

is actually "releasing the lock". So this is not really about failing, as it is about releasing the lock explicitly. I find this a lot easier to read and reason about the code.

like image 146
Eugene Avatar answered Nov 09 '22 22:11

Eugene


This code - and literally any other Java code before version 11 - could fail as a result of the deprecated Thread.stop method being called from another thread. This results in a ThreadDeath error being thrown in the targeted thread, potentially at any time. However, the thread does at least stay alive long enough for the finally block to execute.

The Thread.stop method is deprecated because this behaviour makes it "inherently unsafe":

Why is Thread.stop deprecated?

Because it is inherently unsafe. Stopping a thread causes it to unlock all the monitors that it has locked. (The monitors are unlocked as the ThreadDeath exception propagates up the stack.) If any of the objects previously protected by these monitors were in an inconsistent state, other threads may now view these objects in an inconsistent state. Such objects are said to be damaged. When threads operate on damaged objects, arbitrary behavior can result. This behavior may be subtle and difficult to detect, or it may be pronounced. Unlike other unchecked exceptions, ThreadDeath kills threads silently; thus, the user has no warning that his program may be corrupted. The corruption can manifest itself at any time after the actual damage occurs, even hours or days in the future.

In theory the code could have been written this way as an attempted defense against leaving the object in an invalid state if the thread it is executed in is stopped from another thread. That said, it is very difficult to guarantee a valid state if Thread.stop could be called at any time, and not very common to even attempt to do so, so it's not likely that this was the author's intention. (If it was, the code would probably have a comment explaining it.)

like image 45
kaya3 Avatar answered Nov 09 '22 22:11

kaya3