diff --git a/core/src/main/java/fj/P1.java b/core/src/main/java/fj/P1.java index 711b1436..84fedd91 100644 --- a/core/src/main/java/fj/P1.java +++ b/core/src/main/java/fj/P1.java @@ -223,9 +223,12 @@ public A _1() { A a = v != null ? v.get() : null; if (a == null) synchronized (latch) { - if (v == null || v.get() == null) + if (v == null || v.get() == null) { a = self._1(); - v = new SoftReference(a); + v = new SoftReference(a); + } else { + a = v.get(); + } } return a; } diff --git a/core/src/test/java/fj/P1Test.java b/core/src/test/java/fj/P1Test.java new file mode 100644 index 00000000..2a161777 --- /dev/null +++ b/core/src/test/java/fj/P1Test.java @@ -0,0 +1,31 @@ +package fj; + +import org.junit.Test; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +public final class P1Test { + + @Test + public void bug105() throws Exception { + final P1 p1 = P.p("Foo").memo(); + final AtomicInteger nullCounter = new AtomicInteger(); + ExecutorService executorService = Executors.newCachedThreadPool(); + + for (int i = 0; i < 10000; i++) { + executorService.submit(() -> { + if (p1._1() == null) { + nullCounter.incrementAndGet(); + } + }); + } + + executorService.shutdown(); + executorService.awaitTermination(10, TimeUnit.DAYS); + + org.junit.Assert.assertEquals("Race condition in P1.memo()", 0, nullCounter.get()); + } +}