소스 검색

tests

fix: LazyReference#concurrent
fix: LazyReference#shared
Ranides Atterwim 10 년 전
부모
커밋
c2ee6ecec1

+ 1 - 1
assira/pom.xml

@@ -40,7 +40,6 @@
                                 <include>net/ranides/assira/collection/lists/IntRange*</include>
                                 <include>net/ranides/assira/collection/utils/**</include>
                                 <include>net/ranides/assira/functional/**</include>
-                                <include>net/ranides/assira/generic/LazyReference*</include>
                                 <include>net/ranides/assira/generic/SerializationUtils*</include>
                                 <include>net/ranides/assira/generic/Wrapper*</include>
                                 <include>net/ranides/assira/io/FileUtils*</include>
@@ -67,6 +66,7 @@
 								<exclude>**/EventDispatcherTest.java</exclude>
 								<exclude>**/EventProactorTest.java</exclude>
 								<exclude>**/EventReactorTest.java</exclude>
+								<exclude>**/LazyReferenceTest.java</exclude>
 							</excludes>
 						</configuration>
 					</plugin>

+ 15 - 14
assira/src/main/java/net/ranides/assira/generic/LazyReference.java

@@ -16,8 +16,6 @@ import java.util.function.Supplier;
  * @param <T>
  */
 public final class LazyReference {
-    
-    private static enum State { UNDEFINED_1, UNDEFINED_2 }
 
     private LazyReference() {
         /* utility class */
@@ -62,18 +60,20 @@ public final class LazyReference {
      */
     @SuppressWarnings("unchecked")
     public static <T> Supplier<T> concurrent(Supplier<T> supplier) {
-        AtomicReference<Object> ref = new AtomicReference<>(State.UNDEFINED_1);
+        AtomicReference<T> ref = new AtomicReference<>(null);
         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();
-        };
+			T temp = ref.get();
+			if (temp == null) {
+				temp = supplier.get();
+				if (ref.compareAndSet(null, temp)) {
+					return temp;
+				} else {
+					return ref.get();
+				}
+			} else {
+				return temp;
+			}
+		};
     }
     
     private static class NonLocking<T> implements Supplier<T> {
@@ -114,7 +114,8 @@ public final class LazyReference {
             T temp = ref;
             if(null == temp) {
                 synchronized(this) {
-                    if(null == ref) {
+					temp = ref;
+                    if(temp == null) {
                         ref = temp = supplier.get();
                     }
                 }

+ 132 - 0
assira/src/test/java/net/ranides/assira/generic/LazyReferenceTest.java

@@ -0,0 +1,132 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.generic;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import junit.framework.Assert;
+import static net.ranides.assira.junit.NewAssert.*;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public class LazyReferenceTest {
+
+	@Test
+	public void testUnique() {
+		AtomicInteger ai = new AtomicInteger(5);
+		Supplier<Integer> ref = LazyReference.unique(() -> ai.getAndIncrement());
+		assertEquals(5, ref.get().intValue());
+		assertEquals(5, ref.get().intValue());
+		assertEquals(5, ref.get().intValue());
+	}
+	
+	@Test
+	public void testLocal() throws InterruptedException, Throwable {
+		List<Throwable> errors = Collections.synchronizedList(new ArrayList<>());
+		
+		AtomicInteger ai = new AtomicInteger(5);
+		Supplier<Integer> ref = LazyReference.local(() -> ai.getAndIncrement());
+		
+		thread(0, errors::add, ()->{
+			for(int i=0; i<5; i++) {
+				sleep(50);
+				assertEquals(5, ref.get().intValue());
+			}
+		});
+		thread(50, errors::add, ()->{
+			for(int i=0; i<5; i++) {
+				sleep(50);
+				assertEquals(6, ref.get().intValue());
+			}
+		});
+		thread(100, errors::add, ()->{
+			for(int i=0; i<5; i++) {
+				sleep(50);
+				assertEquals(7, ref.get().intValue());
+			}
+		}).join();
+
+		if(!errors.isEmpty()) {
+			throw errors.get(0);
+		}
+	}
+	
+	@Test
+	public void testShared() throws InterruptedException, Throwable {
+		List<Throwable> errors = Collections.synchronizedList(new ArrayList<>());
+		
+		AtomicInteger ai = new AtomicInteger(5);
+		Supplier<Integer> ref = LazyReference.shared(() -> ai.getAndIncrement());
+		
+		for(int t=0; t<20; t++) {
+			thread(50, errors::add, ()->{
+				for(int i=0; i<10; i++) {
+					sleep(50);
+					Integer v = ref.get();
+					assertEquals(5, v.intValue());
+				}
+			});
+		}
+		sleep(1000);
+
+		if(!errors.isEmpty()) {
+			throw errors.get(0);
+		}
+	}
+	
+	@Test
+	public void testConcurrent() throws InterruptedException, Throwable {
+		List<Throwable> errors = Collections.synchronizedList(new ArrayList<>());
+		
+		AtomicInteger ai = new AtomicInteger(5);
+		Supplier<Integer> ref = LazyReference.concurrent(() -> ai.getAndIncrement());
+
+		for(int t=0; t<10; t++) {
+			thread(50, errors::add, ()->{
+				for(int i=0; i<10; i++) {
+					sleep(10);
+					int v = ref.get().intValue();
+					if(v > 10) {
+						fail("ref.value = " + v);
+					}
+				}
+			});
+		}
+		sleep(500);
+
+		if(!errors.isEmpty()) {
+			throw errors.get(0);
+		}
+	}
+	
+	private static void sleep(long ms) {
+		try {
+			Thread.sleep(ms);
+		} catch (InterruptedException $0) {
+			/* do nothing */
+		}
+	}
+	
+	private static Thread thread(long delay, Consumer<Throwable> handler, Runnable runnable) {
+		Thread thread = new Thread(()->{
+			sleep(delay);
+			runnable.run();
+		});
+		thread.setUncaughtExceptionHandler((t,e) -> handler.accept(e));
+		thread.start();
+		return thread;
+	}
+	
+}

+ 0 - 2
assira/src/test/java/net/ranides/assira/generic/SerializationUtilsTest.java

@@ -67,8 +67,6 @@ public class SerializationUtilsTest {
 		
 		assertTrue( ic1.size() < ic2.size());
 		assertTrue( ic1.element()< ic2.element());
-		
-		
 	}
 	
 }