diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..883ea48 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +target/ +/*.iml \ No newline at end of file diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index b38c85c..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -HW \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index cdc4be7..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml deleted file mode 100644 index e7bedf3..0000000 --- a/.idea/copyright/profiles_settings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 6360958..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.8 - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index e19c5f2..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index 5c52d0b..0000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,301 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1455284315959 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/JavaHW.iml b/JavaHW.iml deleted file mode 100644 index 73f608b..0000000 --- a/JavaHW.iml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/pom.xml b/pom.xml index 91c9624..31f50f7 100644 --- a/pom.xml +++ b/pom.xml @@ -8,5 +8,12 @@ hw 1.0-SNAPSHOT + + + junit + junit + 4.12 + + \ No newline at end of file diff --git a/src/main/java/Lazy.java b/src/main/java/Lazy.java new file mode 100644 index 0000000..ca03b25 --- /dev/null +++ b/src/main/java/Lazy.java @@ -0,0 +1,7 @@ +/** + * Created by urijkravcenko on 12/02/16. + */ + +public interface Lazy { + T get(); +} diff --git a/src/main/java/LazyFactory.java b/src/main/java/LazyFactory.java new file mode 100644 index 0000000..c039aac --- /dev/null +++ b/src/main/java/LazyFactory.java @@ -0,0 +1,80 @@ +import java.util.concurrent.atomic.AtomicMarkableReference; +import java.util.function.Supplier; + +/** + * Created by urijkravcenko on 12/02/16. + */ + +public class LazyFactory { + + abstract private static class MyLazy implements Lazy { + boolean got = false; + Object result = null; + + MyLazy(Supplier supplier) { + result = supplier; + } + } + + public static Lazy createLazy1(Supplier supplier) { + + return new MyLazy(supplier) { + + public T get() { + if (!got) { + got = true; + result = ((Supplier) result).get(); + } + return (T) result; + } + + }; + } + + public static Lazy createLazy2(Supplier supplier) { + + return new MyLazy(supplier) { + public T get() { + if (!got) { + synchronized (this) { + if (!got) { + result = ((Supplier) result).get(); + got = true; + } + } + } + return (T) result; + } + + }; + } + + abstract private static class MyOtherLazy implements Lazy { + AtomicMarkableReference result = new AtomicMarkableReference(null, false); + + MyOtherLazy(Supplier supplier) { + result.set(supplier, false); + } + + } + + public static Lazy createLazy3(Supplier supplier) { + + return new MyOtherLazy(supplier) { + + public T get() { + boolean currentMark = result.isMarked(); + Object currentObject = result.getReference(); + if (currentMark != result.isMarked()) { + currentMark = result.isMarked(); + } + if (!currentMark) { + T newResult = ((Supplier) currentObject).get(); + result.compareAndSet(currentObject, newResult, currentMark, true); + } + return (T) result.getReference(); + } + }; + } + +} diff --git a/src/test/java/LazyFactoryTest.java b/src/test/java/LazyFactoryTest.java new file mode 100644 index 0000000..dd96c48 --- /dev/null +++ b/src/test/java/LazyFactoryTest.java @@ -0,0 +1,362 @@ +import org.junit.Assert; + +import java.util.ArrayList; +import java.util.Random; +import java.util.concurrent.CyclicBarrier; +import java.util.function.Supplier; + +import static org.junit.Assert.*; + +/** + * Created by urijkravcenko on 12/02/16. + */ +public class LazyFactoryTest { + + private static class LazyFactoryTester1 { + private int runs = 0; + + LazyFactoryTester1(final Supplier supplier) { + runs = 0; + Lazy myLazy = LazyFactory.createLazy1(new Supplier() { + public T get() { + runs++; + return supplier.get(); + } + }); + T answer = myLazy.get(); + for (int i = 0; i < 100; i++) { + assertSame(answer, myLazy.get()); + } + + assertEquals(1, runs); + } + } + + @org.junit.Test + public void testCreateLazy1Null() { + new LazyFactoryTester1(new Supplier() { + public Integer get() { + return null; + } + }); + } + + @org.junit.Test + public void testCreateLazy1SameIntegers() { + new LazyFactoryTester1(new Supplier() { + public Integer get() { + return 1; + } + }); + } + + @org.junit.Test + public void testCreateLazy1RandomInteger() { + new LazyFactoryTester1(new Supplier() { + Random random = new Random(123); + + public Integer get() { + return random.nextInt(); + } + }); + } + + @org.junit.Test + public void testNothing1() { + LazyFactory.createLazy1(new Supplier() { + + @Override + public String get() { + Assert.fail(); + return null; + } + }); + } + + + private static class LazyFactoryTester2 { + private volatile int runs; + private static final int n = 10; + private ArrayList answer = new ArrayList(); + + LazyFactoryTester2(final Supplier supplier) { + final Lazy myLazy = LazyFactory.createLazy2(new Supplier() { + public T get() { + runs++; + return supplier.get(); + } + }); + final CyclicBarrier barrier = new CyclicBarrier(n); + ArrayList threads = new ArrayList(n); + for (int i = 0; i < n; i++) { + final int finalI = i; + answer.add(null); + threads.add(new Thread(new Runnable() { + public void run() { + try { + barrier.await(); + } catch (Exception e) { + e.printStackTrace(); + } + answer.set(finalI, myLazy.get()); + for (int i = 0; i < 100; ++i) { + assertSame(answer.get(finalI), myLazy.get()); + } + } + })); + threads.get(i).start(); + } + for (int i = 0; i < n; i++) { + try { + threads.get(i).join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + assertEquals(1, runs); + for (int i = 0; i < n - 1; i++) { + assertSame(answer.get(i), answer.get(i + 1)); + } + + } + } + + @org.junit.Test + public void testCreateLazy2Null() { + new LazyFactoryTester2(new Supplier() { + public Integer get() { + return null; + } + }); + } + + @org.junit.Test + public void testCreateLazy2SameInteger() { + new LazyFactoryTester2(new Supplier() { + public Integer get() { + return 1; + } + }); + } + + @org.junit.Test + public void testCreateLazy2RandomInteger() { + new LazyFactoryTester2(new Supplier() { + Random random = new Random(123); + + public Integer get() { + return random.nextInt(); + } + }); + } + + @org.junit.Test + public void testCreateLazy2NullThenString() { + new LazyFactoryTester2(new Supplier() { + boolean flag = true; + + public String get() { + if (flag) { + flag = false; + return null; + } + return "abacaba"; + } + }); + } + + @org.junit.Test + public void testCreateLazy2StringThenNull() { + new LazyFactoryTester2(new Supplier() { + boolean flag = true; + + public String get() { + if (flag) { + flag = false; + return "abacaba"; + } + return null; + } + }); + } + + @org.junit.Test + public void testCreateLazy2StringOrNullRandomly() { + new LazyFactoryTester2(new Supplier() { + Random random = new Random(123); + + public String get() { + if (random.nextBoolean()) { + return "abacaba"; + } + return null; + } + }); + } + + @org.junit.Test + public void testNothing2() { + LazyFactory.createLazy2(new Supplier() { + + @Override + public String get() { + Assert.fail(); + return null; + } + }); + } + + static class LazyFactoryTester3 { + private static final int n = 10; + private ArrayList answer = new ArrayList(); + + LazyFactoryTester3(final Supplier supplier) { + final Lazy myLazy = LazyFactory.createLazy3(supplier); + final CyclicBarrier barrier = new CyclicBarrier(n); + ArrayList threads = new ArrayList(n); + for (int i = 0; i < n; i++) { + final int finalI = i; + answer.add(null); + threads.add(new Thread(new Runnable() { + public void run() { + try { + barrier.await(); + } catch (Exception e) { + e.printStackTrace(); + } + answer.set(finalI, myLazy.get()); + for (int i = 0; i < 100; ++i) { + assertSame(answer.get(finalI), myLazy.get()); + } + } + })); + threads.get(i).start(); + } + for (int i = 0; i < n; ++i) { + try { + threads.get(i).join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + for (int i = 0; i < n - 1; ++i) { + assertSame(answer.get(i), answer.get(i + 1)); + } + + } + } + + @org.junit.Test + public void testCreateLazy3Null() { + new LazyFactoryTester3(new Supplier() { + public Integer get() { + return null; + } + }); + } + + @org.junit.Test + public void testCreateLazy3SameInteger() { + new LazyFactoryTester3(new Supplier() { + public Integer get() { + return 1; + } + }); + } + + @org.junit.Test + public void testCreateLazy3RandomInteger() { + new LazyFactoryTester3(new Supplier() { + Random random = new Random(123); + + public Integer get() { + return random.nextInt(); + } + }); + } + + @org.junit.Test + public void testCreateLazy3NullThenString() { + new LazyFactoryTester3(new Supplier() { + boolean flag = true; + + public String get() { + if (flag) { + flag = false; + return null; + } + return "abacaba"; + } + }); + } + + @org.junit.Test + public void testCreateLazy3StingThenNull() { + new LazyFactoryTester3(new Supplier() { + boolean flag = true; + + public String get() { + if (flag) { + flag = false; + return "abacaba"; + } + return null; + } + }); + } + + @org.junit.Test + public void testCreateLazy3NullOrStringRandom() { + new LazyFactoryTester3(new Supplier() { + Random random = new Random(123); + + public String get() { + if (random.nextBoolean()) { + return "abacaba"; + } + return null; + } + }); + } + + @org.junit.Test + public void testCreateLazy3Supplier() { + new LazyFactoryTester3>(new Supplier>() { + public Supplier get() { + return new Supplier() { + Random random = new Random(123); + + public String get() { + if (random.nextBoolean()) { + return "abacaba"; + } + return null; + } + }; + } + }); + } + + @org.junit.Test + public void testCreateLazy3SupplierOrNullRandomly() { + new LazyFactoryTester3>(new Supplier>() { + Random random = new Random(123); + + public Supplier get() { + if (random.nextBoolean()) { + return null; + } + return new Supplier() { + Random random = new Random(1234); + + public String get() { + if (random.nextBoolean()) { + return "abacaba"; + } + return null; + } + }; + } + }); + } +} \ No newline at end of file