فهرست منبع

new: LazyReference

Ranides Atterwim 10 سال پیش
والد
کامیت
322123adb5
1فایلهای تغییر یافته به همراه128 افزوده شده و 0 حذف شده
  1. 128 0
      assira/src/main/java/net/ranides/assira/generic/LazyReference.java

+ 128 - 0
assira/src/main/java/net/ranides/assira/generic/LazyReference.java

@@ -0,0 +1,128 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/everything
+ */
+
+package net.ranides.assira.generic;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @param <T>
+ */
+public final class LazyReference {
+    
+    private static enum State { UNDEFINED_1, UNDEFINED_2 }
+
+    private LazyReference() {
+        /* utility class */
+    }
+    
+    /**
+     * Initialization is unsynchronized. There is no guarantee about thread-safety.
+     * @param <T>
+     * @param supplier
+     * @return 
+     */
+     
+    public static <T> Supplier<T> unique(Supplier<T> supplier) {
+        return new NonLocking<>(supplier);
+    }
+    
+    /**
+     * Initialization is done once per thread. Every thread will have different thread-local object.
+     * @param <T>
+     * @param supplier
+     * @return 
+     */
+    public static <T> Supplier<T> local(Supplier<T> supplier) {
+        return ThreadLocal.withInitial(supplier)::get;
+    }
+
+    /**
+     * Initialization is synchronized using correctly implemented "double checked locking". 
+     * @param <T>
+     * @param supplier
+     * @return 
+     */
+    public static <T> Supplier<T> shared(Supplier<T> supplier) {
+        return new Shared<>(supplier);
+    }
+
+    /**
+     * Initialization is lock-free. There is a chance of spurious "double initialization".
+     * @param <T>
+     * @param supplier
+     * @return 
+     */
+    public static <T> Supplier<T> concurent(Supplier<T> supplier) {
+        AtomicReference<Object> ref = new AtomicReference<>(State.UNDEFINED_1);
+        return () -> {
+            if( ref.compareAndSet(State.UNDEFINED_1, State.UNDEFINED_2) ) {
+                ref.set(supplier.get() );
+                return (T)ref.get();
+            }
+            if( ref.compareAndSet(State.UNDEFINED_2, State.UNDEFINED_1) ) {
+                ref.set(supplier.get() );
+                return (T)ref.get();
+            }
+            return (T)ref.get();
+        };
+    }
+    
+    private static class NonLocking<T> implements Supplier<T> {
+
+        private final Supplier<T> supplier;
+        
+        private T ret;
+
+        public NonLocking(Supplier<T> supplier) {
+            this.supplier = supplier;
+        }
+
+        @Override
+        public T get() {
+            if( ret == null) {
+                ret = supplier.get();
+            }
+            return ret;
+        }
+
+    }
+    
+    private static class Shared<T> implements Supplier<T> {
+        
+        // works in JDK5 +
+        // http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
+        
+        private final Supplier<T> supplier;
+
+        private volatile T ref = null;
+
+        public Shared(Supplier<T> supplier) {
+            this.supplier = supplier;
+        }
+
+        @Override
+        public T get() {
+            T temp = ref;
+            if(null == temp) {
+                synchronized(this) {
+                    if(null == ref) {
+                        ref = temp = supplier.get();
+                    }
+                }
+            }
+            return temp;
+        }
+
+    }
+
+
+}