1 10 package org.picocontainer.defaults; 11 12 import java.util.ArrayList ; 13 import java.util.Collections ; 14 import java.util.Date ; 15 import java.util.List ; 16 17 import junit.framework.TestCase; 18 19 import org.picocontainer.ComponentAdapter; 20 import org.picocontainer.PicoContainer; 21 22 28 public class SynchronizedComponentAdapterTestCase extends TestCase { 29 private Runner[] runner = new Runner[3]; 30 private int blockerCounter = 0; 31 32 class Runner implements Runnable { 33 public RuntimeException exception; 34 public Blocker blocker; 35 private PicoContainer pico; 36 37 public Runner(PicoContainer pico) { 38 this.pico = pico; 39 } 40 41 public void run() { 42 try { 43 blocker = (Blocker) pico.getComponentInstance("key"); 44 } catch (RuntimeException e) { 45 exception = e; 46 } 47 } 48 } 49 50 public class Blocker { 51 public Blocker() throws InterruptedException { 52 final Thread thread = Thread.currentThread(); 53 synchronized (thread) { 54 SynchronizedComponentAdapterTestCase.this.blockerCounter++; 55 thread.wait(); 56 } 57 } 58 } 59 60 private void initTest(ComponentAdapter componentAdapter) throws InterruptedException { 61 DefaultPicoContainer pico = new DefaultPicoContainer(); 62 pico.registerComponentInstance(this); 63 pico.registerComponent(componentAdapter); 64 blockerCounter = 0; 65 66 for(int i = 0; i < runner.length; ++i) { 67 runner[i] = new Runner(pico); 68 } 69 70 Thread racer[] = new Thread [runner.length]; 71 for(int i = 0; i < racer.length; ++i) { 72 racer[i] = new Thread (runner[i]); 73 } 74 75 for(int i = 0; i < racer.length; ++i) { 76 racer[i].start(); 77 Thread.sleep(250); 78 } 79 80 for(int i = 0; i < racer.length; ++i) { 81 synchronized (racer[i]) { 82 racer[i].notify(); 83 } 84 } 85 86 for(int i = 0; i < racer.length; ++i) { 87 racer[i].join(); 88 } 89 } 90 91 public void testRaceConditionIsHandledBySynchronizedComponentAdapter() throws InterruptedException { 92 ComponentAdapter componentAdapter = new CachingComponentAdapter(new ConstructorInjectionComponentAdapter("key", Blocker.class)); 93 SynchronizedComponentAdapter synchronizedComponentAdapter = new SynchronizedComponentAdapter(componentAdapter); 94 initTest(synchronizedComponentAdapter); 95 96 assertEquals(1, blockerCounter); 97 for(int i = 0; i < runner.length; ++i) { 98 assertNull(runner[i].exception); 99 } 100 for(int i = 0; i < runner.length; ++i) { 101 assertNotNull(runner[i].blocker); 102 } 103 for(int i = 1; i < runner.length; ++i) { 104 assertSame(runner[0].blocker, runner[i].blocker); 105 } 106 } 107 108 public void testRaceConditionIsNotHandledWithoutSynchronizedComponentAdapter() throws InterruptedException { 109 ComponentAdapter componentAdapter = new CachingComponentAdapter(new ConstructorInjectionComponentAdapter("key", Blocker.class)); 110 initTest(componentAdapter); 111 112 assertNull(runner[0].exception); 113 assertEquals(3, blockerCounter); 114 for(int i = 1; i < runner.length; ++i) { 115 assertNull(runner[i].exception); 116 } 117 } 118 119 public void THIS_NATURALLY_FAILS_testSingletonCreationRace() throws InterruptedException { 120 DefaultPicoContainer pico = new DefaultPicoContainer(); 121 pico.registerComponentImplementation("slow", SlowCtor.class); 122 runConcurrencyTest(pico); 123 } 124 125 public void THIS_NATURALLY_FAILS_testSingletonCreationWithSynchronizedAdapter() throws InterruptedException { 126 DefaultPicoContainer pico = new DefaultPicoContainer(); 127 pico.registerComponent(new CachingComponentAdapter(new SynchronizedComponentAdapter(new ConstructorInjectionComponentAdapter("slow", SlowCtor.class)))); 128 runConcurrencyTest(pico); 129 } 130 131 public void testSingletonCreationWithSynchronizedAdapterAndDoubleLocking() throws InterruptedException { 133 DefaultPicoContainer pico = new DefaultPicoContainer(); 134 pico.registerComponent(new SynchronizedComponentAdapter(new CachingComponentAdapter(new SynchronizedComponentAdapter(new ConstructorInjectionComponentAdapter("slow", SlowCtor.class))))); 135 runConcurrencyTest(pico); 136 } 137 138 public void testSingletonCreationWithSynchronizedAdapterOutside() throws InterruptedException { 139 DefaultPicoContainer pico = new DefaultPicoContainer(); 140 pico.registerComponent(new SynchronizedComponentAdapter(new CachingComponentAdapter(new ConstructorInjectionComponentAdapter("slow", SlowCtor.class)))); 141 runConcurrencyTest(pico); 142 } 143 144 public void testSingletonCreationWithSynchronizedAdapterOutsideUsingFactory() throws InterruptedException { 145 DefaultPicoContainer pico = new DefaultPicoContainer( 146 new SynchronizedComponentAdapterFactory( 147 new CachingComponentAdapterFactory( 148 new ConstructorInjectionComponentAdapterFactory() 149 ) 150 ) 151 ); 152 pico.registerComponentImplementation("slow", SlowCtor.class); 153 runConcurrencyTest(pico); 154 } 155 156 private void runConcurrencyTest(final DefaultPicoContainer pico) throws InterruptedException { 157 int size = 10; 158 159 Thread [] threads = new Thread [size]; 160 161 final List out = Collections.synchronizedList(new ArrayList ()); 162 163 for (int i = 0; i < size; i++) { 164 165 threads[i] = new Thread (new Runnable () { 166 public void run() { 167 try { 168 out.add(pico.getComponentInstance("slow")); 169 } catch (Exception e) { 170 out.add(new Date ()); } 173 } 174 }); 175 } 176 177 for (int i = 0; i < threads.length; i++) { 178 threads[i].start(); 179 } 180 for (int i = 0; i < threads.length; i++) { 181 threads[i].join(); 182 } 183 184 List differentInstances = new ArrayList (); 185 186 for (int i = 0; i < out.size(); i++) { 187 Object o = out.get(i); 188 189 if (!differentInstances.contains(o)) 190 differentInstances.add(o); 191 } 192 193 assertTrue("Only one singleton instance was created [we have " + differentInstances.size() + "]", differentInstances.size() == 1); 194 } 195 196 public static class SlowCtor { 197 public SlowCtor() throws InterruptedException { 198 Thread.sleep(50); 199 } 200 } 201 } 202 | Popular Tags |