From 8af9ff1e34023a8994de9229a1034422ef0fd2de Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Giraudeau Date: Tue, 14 Apr 2015 08:08:37 +0200 Subject: [PATCH] Alternate take at fixing #108 avoid repetitive locks in case of null return by delegate. --- core/src/main/java/fj/P1.java | 67 ++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/fj/P1.java b/core/src/main/java/fj/P1.java index 84fedd91..4cb64aeb 100644 --- a/core/src/main/java/fj/P1.java +++ b/core/src/main/java/fj/P1.java @@ -207,32 +207,59 @@ public P1 map(final F f) { return P.lazy(u -> f.f(self._1())); } + private static final class MemoizingP1 extends P1 { + + private final F0 delegate; + + // 0: uninitialized, -1: initialized but value is null, 1: initialized and value is non-null + private volatile byte state = 0; + + // "value" does not need to be volatile; visibility piggy-backs + // on volatile read of "state". Contains a non-null value from delegate. + private SoftReference value; + + MemoizingP1(final F0 delegate) { + this.delegate = delegate; + } + + @Override + public A _1() { + final byte s = state; + if (s == -1) { + return null; + } + A a; + // A 2-field variant of Double Checked Locking. + if ((s == 0) || ((a = value.get()) == null)) { + synchronized (this) { + if ((state == 0) || ((a = value.get()) == null)) { + a = delegate.f(); + if (a == null) { + state = -1; + } else { + final SoftReference tmp = new SoftReference(a); + value = tmp; + state = 1; + } + } + } + } + return a; + } + + @Override + public P1 memo() { + return this; + } + } + /** * Provides a memoising P1 that remembers its value. * * @return A P1 that calls this P1 once and remembers the value for subsequent calls. */ public P1 memo() { - final P1 self = this; - return new P1() { - private final Object latch = new Object(); - @SuppressWarnings({"InstanceVariableMayNotBeInitialized"}) - private volatile SoftReference v; - - public A _1() { - A a = v != null ? v.get() : null; - if (a == null) - synchronized (latch) { - if (v == null || v.get() == null) { - a = self._1(); - v = new SoftReference(a); - } else { - a = v.get(); - } - } - return a; - } - }; + return new MemoizingP1<>(this); } static P1 memo(F f) {