I have a complex map, which doesn't need locking for the frequent gets and infrequent changes, because the keys uniquely determine the behavior of their referenced elements.
That is, if the key is the same, the structure it references will always have the same behavior. In fact, the key is immutable final and the referenced value is effectively final and/or threadsafe.
Lets say I have a volatile reference to the underlying volatile array of references in my custom hashmap. My hashmap algorithm for this array uses the ar.length member as the modulus so if in the get function, the caller sees a non-current array, all of its references will still be good, and still obey the hashing slots, so if it succeeds without mutex to get a non-null value, that's the right one.
My plan is whenever a get fails, the caller then constructs the correct value for the key does a put which does locking relative to other puts and stuffs an object into the array. Just before exiting the critical section the put code reassigns the volatile array field "ar" to itself, hopefully as a message to the compiler and hotspot compiler to create a fence relative to the gets which use the volatile array reference to find a hashed value.
This will work as long as the compiler doesn't nop the "ar = ar" assignment:
private volatile Object[] ar;
public Object get (Object key)
{
Object[] ar = this.ar;
// get the value from the correct hash slot
}
public synchronized Object put (Object key, Object val) {
{
... stuff a new object into the correct hash slot
ar = ar; // will the compiler truly compile this statement with
// normal volatile fencing relative to the get function??
... if a race condition causes a value to already be mapped, return and use that
... rather than the one we created and passed to put (different than normal put
... contract)
}