I would be interested in his basic locking principle.
I think it has the same problem. He is assuming that if he .gets() an
even number, then no write lock has happened.
Well, he assumes no write is in progress. A write would have definitely
happened if writeCounter was 2, for example.
However, that isn't guaranteed.
I don't see how it isn't guaranteed. get() and set() on an
AtomicInteger create a happens-before relationship, just like a
volatile. Both the variable itself and the map should be protected on a
"good" read. I'm concerned about what happens when there's a write (a
reader could be in there too) and what happens on a "bad" read.
I didn't see where he creates/publishes writeCounter and lock. I assume
they're safely published as final instance fields somewhere. That
shouldn't be a problem.
This is to handle the case where the reader reads the counter before
and after a write. It needs to be able to tell something changed.
Good point, I realized this after I posted.
True, he is assuming that a .get() on an unstable map won't do
anything dangerous, like cause an infinite loop.
That's what I was thinking. With folks like Brian Goetz and Bartosz
saying the system can simply invent values, it's hard to analyze the
resulting code for any kind of deterministic behavior. Esp. because
Java is a step away from the machine, and I don't know exactly what sort
of operations are going to be executed.
In particular, during the write, if a reader is also present, I wonder
if the writer could "see" a bad read due to the reader present, and then
"finalize" that bad read and write it to memory. Stuff like this is
hard to analyze.
*IF* you assume that the read operation actually returns, and doesn't
throw an exception, or melt some other part of the code (like the
writer), *then* I think you can say that the update will be detected by
the reader, and the operation will be re-tried. This does seem to
eventually guarantee an uncontended read of the map, provided writes
don't happen "too frequently," which must be the case for this sort of
lock-free code, or it isn't going to work.
So, yes I think it works if you're prepared to make some assumptions
about the behavior of the JVM. However, I don't think anyone on this
list should be making those assumptions. Better safe than sorry.
I was just wondering about his basic method.
ConcurrentHashMap uses a totally different technique. It "stripes" the
map into several smaller maps, each of which has its own lock.
Therefore the chance that two threads will "collide" and need the same
lock is reduced. Striping locks is a much easier technique, easier to
analyze and very effective afaik. Java Concurrency in Practice talks
about this in some detail. It's worth checking out.
After you're done with striping, check out ConcurrentSkipListMap, and
look up some of the basic info on the skip list algorithm (Sedgewick is
good). More crazy techniques.