PageRenderTime 26ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/src/test/java/com/atlassian/util/concurrent/LazyReferenceTest.java

https://bitbucket.org/atlassian/atlassian-util-concurrent
Java | 295 lines | 222 code | 35 blank | 38 comment | 8 complexity | 55b6a1978ce955a1bb5bf51982856e7b MD5 | raw file
Possible License(s): Apache-2.0
  1. package com.atlassian.util.concurrent;
  2. import static com.atlassian.util.concurrent.TestUtil.pause;
  3. import static org.junit.Assert.assertEquals;
  4. import static org.junit.Assert.assertFalse;
  5. import static org.junit.Assert.assertNotNull;
  6. import static org.junit.Assert.assertNull;
  7. import static org.junit.Assert.assertSame;
  8. import static org.junit.Assert.assertTrue;
  9. import static org.junit.Assert.fail;
  10. import java.util.ArrayList;
  11. import java.util.List;
  12. import java.util.concurrent.Callable;
  13. import java.util.concurrent.CancellationException;
  14. import java.util.concurrent.CountDownLatch;
  15. import java.util.concurrent.ExecutionException;
  16. import java.util.concurrent.ExecutorService;
  17. import java.util.concurrent.Executors;
  18. import java.util.concurrent.Future;
  19. import java.util.concurrent.atomic.AtomicInteger;
  20. import java.util.concurrent.atomic.AtomicReference;
  21. import org.junit.Test;
  22. public class LazyReferenceTest {
  23. /**
  24. * Used to pound the tests
  25. *
  26. * @param args ignored
  27. * @throws Exception
  28. */
  29. // public static void main(final String[] args) throws Exception {
  30. // final LazyReferenceTest test = new LazyReferenceTest();
  31. // for (int i = 0; i < 10000; i++) {
  32. // // test.concurrentCreate();
  33. // // test.getInterruptibly();
  34. // test.getNotInterruptable();
  35. // }
  36. // }
  37. @Test public void concurrentCreate() throws Exception {
  38. final int nThreads = 40;
  39. final Object[] results = new Object[nThreads];
  40. final AtomicInteger createCallCount = new AtomicInteger(0);
  41. final LazyReference<Object> ref = new LazyReference<Object>() {
  42. @Override protected Object create() {
  43. /*
  44. * We are trying to simulate an expensive object construction call. So
  45. * we do a sleep here. The idea is that we will get many threads to call
  46. * create() at the same time, make create "slow" and then ensure that
  47. * create() method was indeed invoked only once.
  48. */
  49. createCallCount.incrementAndGet();
  50. pause();
  51. pause();
  52. pause();
  53. pause();
  54. pause();
  55. return new Object();
  56. }
  57. };
  58. /*
  59. * pool size must be large enough to accommodate all Callables running in
  60. * parallel as they latch
  61. */
  62. final ExecutorService pool = Executors.newFixedThreadPool(nThreads);
  63. final CountDownLatch latch = new CountDownLatch(nThreads);
  64. final List<Callable<Object>> tasks = new ArrayList<Callable<Object>>(nThreads);
  65. for (int i = 0; i < nThreads; i++) {
  66. final int j = i;
  67. tasks.add(new Callable<Object>() {
  68. public Object call() throws Exception {
  69. /*
  70. * Put in a latch to synchronize all threads and try to get them to
  71. * call ref.get() at the same time (to increase concurrency and make
  72. * this test more useful)
  73. */
  74. latch.countDown();
  75. latch.await();
  76. results[j] = ref.get();
  77. return results[j];
  78. }
  79. });
  80. }
  81. List<Future<Object>> futures = null;
  82. futures = pool.invokeAll(tasks);
  83. // Ensure the create() method was invoked once
  84. assertEquals(1, createCallCount.get());
  85. /*
  86. * Ensure that all the references are the same, use the futures in case of
  87. * exception
  88. */
  89. final Object result = results[0];
  90. for (final Future<Object> future : futures) {
  91. assertSame(result, future.get());
  92. }
  93. for (int i = 0; i < results.length; i++) {
  94. assertSame("got back different reference in '" + i + "' place", result, results[i]);
  95. }
  96. pool.shutdown();
  97. }
  98. @Test public void exception() {
  99. final Exception myException = new Exception();
  100. final LazyReference<Object> ref = new LazyReference<Object>() {
  101. @Override protected Object create() throws Exception {
  102. throw myException;
  103. }
  104. };
  105. try {
  106. ref.get();
  107. fail("RuntimeException should have been thrown");
  108. } catch (final RuntimeException yay) {
  109. assertNotNull(yay.getCause());
  110. assertTrue(myException == yay.getCause());
  111. }
  112. }
  113. @Test public void getNotInterruptable() throws Exception {
  114. final BooleanLatch latch = new BooleanLatch();
  115. final LazyReference<Integer> ref = new LazyReference<Integer>() {
  116. @Override protected Integer create() {
  117. // do not interrupt
  118. while (true) {
  119. try {
  120. latch.await();
  121. return 10;
  122. } catch (final InterruptedException e) {}
  123. }
  124. }
  125. };
  126. final Thread client = new Thread(new Runnable() {
  127. public void run() {
  128. ref.get();
  129. }
  130. }, this.getClass().getName());
  131. client.start();
  132. for (int i = 0; i < 10; i++) {
  133. pause();
  134. assertFalse(ref.isInitialized());
  135. client.interrupt();
  136. }
  137. pause();
  138. assertFalse(ref.isInitialized());
  139. latch.release();
  140. pause();
  141. assertTrue(ref.isInitialized());
  142. final int obj = ref.get();
  143. assertEquals(10, obj);
  144. }
  145. @Test(expected = InterruptedException.class) public void getInterruptiblyThrowsInterrupted() throws Exception {
  146. final LazyReference<String> ref = new LazyReference<String>() {
  147. @Override protected String create() throws Exception {
  148. return "test";
  149. }
  150. };
  151. Thread.currentThread().interrupt();
  152. ref.getInterruptibly();
  153. }
  154. @Test public void getInterruptibly() throws Exception {
  155. final class Result<T> {
  156. final T result;
  157. final Exception exception;
  158. Result(final T result) {
  159. this.result = result;
  160. this.exception = null;
  161. }
  162. Result(final Exception exception) {
  163. this.result = null;
  164. this.exception = exception;
  165. }
  166. }
  167. final BooleanLatch latch = new BooleanLatch();
  168. final LazyReference<Integer> ref = new LazyReference<Integer>() {
  169. @Override protected Integer create() {
  170. // do not interrupt
  171. while (true) {
  172. try {
  173. latch.await();
  174. return 10;
  175. } catch (final InterruptedException e) {}
  176. }
  177. }
  178. };
  179. final AtomicReference<Result<Integer>> result1 = new AtomicReference<Result<Integer>>();
  180. final Thread client1 = new Thread(new Runnable() {
  181. public void run() {
  182. try {
  183. result1.compareAndSet(null, new Result<Integer>(ref.getInterruptibly()));
  184. } catch (final Exception e) {
  185. result1.compareAndSet(null, new Result<Integer>(e));
  186. }
  187. }
  188. }, this.getClass().getName());
  189. client1.start();
  190. pause();
  191. final AtomicReference<Result<Integer>> result2 = new AtomicReference<Result<Integer>>();
  192. final Thread client2 = new Thread(new Runnable() {
  193. public void run() {
  194. try {
  195. result2.compareAndSet(null, new Result<Integer>(ref.getInterruptibly()));
  196. } catch (final Exception e) {
  197. result2.compareAndSet(null, new Result<Integer>(e));
  198. }
  199. }
  200. }, this.getClass().getName());
  201. client2.start();
  202. for (int i = 0; i < 10; i++) {
  203. pause();
  204. assertFalse(ref.isInitialized());
  205. client1.interrupt();
  206. client2.interrupt();
  207. }
  208. assertNull(result1.get());
  209. assertNotNull(result2.get().exception);
  210. assertEquals(InterruptedException.class, result2.get().exception.getClass());
  211. pause();
  212. assertFalse(ref.isInitialized());
  213. latch.release();
  214. pause();
  215. assertTrue(ref.isInitialized());
  216. {
  217. final int result = ref.get();
  218. assertEquals(10, result);
  219. }
  220. assertNotNull(result1.get());
  221. assertNotNull(result1.get().result);
  222. {
  223. final int result = result1.get().result;
  224. assertEquals(10, result);
  225. }
  226. }
  227. @Test(expected = CancellationException.class) public void cancellable() throws Exception {
  228. final LazyReference<String> ref = new LazyReference<String>() {
  229. // /CLOVER:OFF
  230. @Override protected String create() throws Exception {
  231. return "created!";
  232. }
  233. // /CLOVER:ON
  234. };
  235. ref.cancel();
  236. ref.get(); // throws
  237. }
  238. @Test public void getNotInterruptible() throws Exception {
  239. final LazyReference<String> ref = new LazyReference<String>() {
  240. @Override protected String create() throws Exception {
  241. return "test!";// exchange.get();
  242. }
  243. };
  244. Thread.currentThread().interrupt();
  245. ref.get();
  246. assertTrue(Thread.interrupted());
  247. }
  248. @Test public void initExConstructorWithBlankExecExCause() throws Exception {
  249. @SuppressWarnings("serial")
  250. final ExecutionException e = new ExecutionException("") {};
  251. final Exception ex = new LazyReference.InitializationException(e);
  252. assertSame(e, ex.getCause());
  253. }
  254. @Test public void initExConstructorWithRealExecExCause() throws Exception {
  255. final NoSuchMethodError er = new NoSuchMethodError();
  256. final ExecutionException e = new ExecutionException("", er);
  257. final Exception ex = new LazyReference.InitializationException(e);
  258. assertSame(er, ex.getCause());
  259. }
  260. }