- T result = myValue;
- if (result != null) return result;
-
- //noinspection SynchronizeOnThis
- synchronized (this) {
- result = myValue;
- if (result == null) {
- final RecursionGuard.StackStamp stamp = ourGuard.markStack();
- result = myComputable.compute();
- if (stamp.mayCacheNow()) {
- myValue = result;
- myComputable = null; // allow gc to clean this up
- }
+ while (true) {
+ T value = myValueRef.get();
+ if (value != null) return value; // value already computed and cached
+
+ final NotNullComputable<T> computable = myComputable;
+ if (computable == null) continue; // computable is null only after some thread succeeds CAS
+
+ final RecursionGuard.StackStamp stamp = ourGuard.markStack();
+ value = computable.compute();
+ if (stamp.mayCacheNow()) {
+ if (myValueRef.compareAndSet(null, value)) { // try to cache value
+ myComputable = null; // if ok, allow gc to clean computable
+ return value;
+ } // if not ok then another thread already set cached value
+ }
+ else {
+ return value; // do not try to cache, just return value