PageRenderTime 51ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/uportal-war/src/test/java/org/jasig/portal/utils/threading/DynamicThreadPoolExecutorTest.java

https://gitlab.com/apachipa/uportal
Java | 315 lines | 195 code | 55 blank | 65 comment | 3 complexity | e98e3e574a13abace44bf217622517c3 MD5 | raw file
  1. /**
  2. * Licensed to Apereo under one or more contributor license
  3. * agreements. See the NOTICE file distributed with this work
  4. * for additional information regarding copyright ownership.
  5. * Apereo licenses this file to you under the Apache License,
  6. * Version 2.0 (the "License"); you may not use this file
  7. * except in compliance with the License. You may obtain a
  8. * copy of the License at the following location:
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. package org.jasig.portal.utils.threading;
  20. import static junit.framework.Assert.assertEquals;
  21. import static junit.framework.Assert.fail;
  22. import java.util.concurrent.CountDownLatch;
  23. import java.util.concurrent.ExecutionException;
  24. import java.util.concurrent.FutureTask;
  25. import java.util.concurrent.RejectedExecutionException;
  26. import java.util.concurrent.RunnableFuture;
  27. import java.util.concurrent.SynchronousQueue;
  28. import java.util.concurrent.ThreadPoolExecutor;
  29. import java.util.concurrent.TimeUnit;
  30. import org.junit.Ignore;
  31. import org.junit.Test;
  32. /**
  33. * Test for {@link ThreadPoolExecutor} that verifies threads are only created on demand
  34. *
  35. * @author Eric Dalquist
  36. * @version $Revision$
  37. */
  38. @Ignore
  39. public class DynamicThreadPoolExecutorTest {
  40. @Test
  41. public void testExecutorsNewCachedThreadPool() throws Exception {
  42. //See Executors.newCachedThreadPool();
  43. final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(0, 2, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()) {
  44. @Override
  45. protected void afterExecute(Runnable r, Throwable t) {
  46. //This happens after Future.get() returns so it reduces the chance for timing issues in the test
  47. final LatchFutureTask lr = (LatchFutureTask)r;
  48. lr.done();
  49. }
  50. @SuppressWarnings("unchecked")
  51. @Override
  52. protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
  53. if (runnable instanceof RunnableFuture) {
  54. return (RunnableFuture<T>)runnable;
  55. }
  56. return super.newTaskFor(runnable, value);
  57. }
  58. };
  59. testThreadPoolExecutor(threadPoolExecutor, false);
  60. }
  61. protected void testThreadPoolExecutor(final ThreadPoolExecutor threadPoolExecutor, boolean queuesAdditional) throws InterruptedException,
  62. ExecutionException {
  63. final ExecutorStats executorStats = new ExecutorStats();
  64. //Nothing going on in a new pool
  65. executorStats.verify(threadPoolExecutor);
  66. //****************************************//
  67. //Schedule task 1
  68. final LatchFutureTask lr1 = LatchFutureTask.create();
  69. threadPoolExecutor.submit(lr1);
  70. //Verify 1 is running
  71. lr1.waitForStart();
  72. executorStats.activeCount++;
  73. executorStats.largestPoolSize++;
  74. executorStats.poolSize++;
  75. executorStats.verify(threadPoolExecutor);
  76. //Verify 1 is stopped
  77. lr1.waitForDone();
  78. //Sadly need to sleep just long enough to let the completed thread get back into the pool
  79. Thread.sleep(5);
  80. executorStats.activeCount--;
  81. executorStats.completedTaskCount++;
  82. executorStats.verify(threadPoolExecutor);
  83. //****************************************//
  84. //Schedule task 2
  85. final LatchFutureTask lr2 = LatchFutureTask.create();
  86. threadPoolExecutor.submit(lr2);
  87. //Verify 2 is running
  88. lr2.waitForStart();
  89. executorStats.activeCount++;
  90. executorStats.verify(threadPoolExecutor);
  91. //Verify 2 is stopped
  92. lr2.waitForDone();
  93. //Sadly need to sleep just long enough to let the completed thread get back into the pool
  94. Thread.sleep(5);
  95. executorStats.activeCount--;
  96. executorStats.completedTaskCount++;
  97. executorStats.verify(threadPoolExecutor);
  98. //****************************************//
  99. //Schedule task 3
  100. final LatchFutureTask lr3 = LatchFutureTask.create();
  101. threadPoolExecutor.submit(lr3);
  102. //Verify 3 is running
  103. lr3.waitForStart();
  104. executorStats.activeCount++;
  105. executorStats.verify(threadPoolExecutor);
  106. //Schedule task 4 concurrently
  107. final LatchFutureTask lr4 = LatchFutureTask.create();
  108. threadPoolExecutor.submit(lr4);
  109. //Verify 4 is running
  110. lr4.waitForStart();
  111. executorStats.activeCount++;
  112. executorStats.poolSize++;
  113. executorStats.largestPoolSize++;
  114. executorStats.verify(threadPoolExecutor);
  115. //Verify 3 is stopped
  116. lr3.waitForDone();
  117. executorStats.activeCount--;
  118. executorStats.completedTaskCount++;
  119. executorStats.verify(threadPoolExecutor);
  120. //Verify 4 is stopped
  121. lr4.waitForDone();
  122. //Sadly need to sleep just long enough to let the completed thread get back into the pool
  123. Thread.sleep(5);
  124. executorStats.activeCount--;
  125. executorStats.completedTaskCount++;
  126. executorStats.verify(threadPoolExecutor);
  127. //****************************************//
  128. //Schedule task 5
  129. final LatchFutureTask lr5 = LatchFutureTask.create();
  130. threadPoolExecutor.submit(lr5);
  131. //Verify 5 is running
  132. lr5.waitForStart();
  133. executorStats.activeCount++;
  134. executorStats.verify(threadPoolExecutor);
  135. //Verify 5 is stopped
  136. lr5.waitForDone();
  137. //Sadly need to sleep just long enough to let the completed thread get back into the pool
  138. Thread.sleep(5);
  139. executorStats.activeCount--;
  140. executorStats.completedTaskCount++;
  141. executorStats.verify(threadPoolExecutor);
  142. //****************************************//
  143. //Schedule task 6
  144. final LatchFutureTask lr6 = LatchFutureTask.create();
  145. threadPoolExecutor.submit(lr6);
  146. //Verify 6 is running
  147. lr6.waitForStart();
  148. executorStats.activeCount++;
  149. executorStats.verify(threadPoolExecutor);
  150. //Schedule task 7 concurrently
  151. final LatchFutureTask lr7 = LatchFutureTask.create();
  152. threadPoolExecutor.submit(lr7);
  153. //Verify 7 is running
  154. lr7.waitForStart();
  155. executorStats.activeCount++;
  156. executorStats.verify(threadPoolExecutor);
  157. //Schedule task 8 concurrently
  158. final LatchFutureTask lr8 = LatchFutureTask.create();
  159. if (queuesAdditional) {
  160. threadPoolExecutor.submit(lr8);
  161. executorStats.verify(threadPoolExecutor);
  162. //Stop 6 to make room in pool for 8
  163. //Verify 6 is stopped
  164. lr6.waitForDone();
  165. executorStats.activeCount--;
  166. executorStats.completedTaskCount++;
  167. executorStats.verify(threadPoolExecutor);
  168. //Verify 8 is running
  169. lr8.waitForStart();
  170. executorStats.activeCount++;
  171. executorStats.verify(threadPoolExecutor);
  172. //Verify 8 is stopped
  173. lr8.waitForDone();
  174. executorStats.activeCount--;
  175. executorStats.completedTaskCount++;
  176. executorStats.verify(threadPoolExecutor);
  177. }
  178. else {
  179. try {
  180. threadPoolExecutor.submit(lr8);
  181. fail("submit should have thrown RejectedExecutionException");
  182. }
  183. catch (RejectedExecutionException e) {
  184. //Expected
  185. }
  186. //Verify 6 is stopped
  187. lr6.waitForDone();
  188. executorStats.activeCount--;
  189. executorStats.completedTaskCount++;
  190. executorStats.verify(threadPoolExecutor);
  191. }
  192. //Verify 7 is stopped
  193. lr7.waitForDone();
  194. //Sadly need to sleep just long enough to let the completed thread get back into the pool
  195. Thread.sleep(5);
  196. executorStats.activeCount--;
  197. executorStats.completedTaskCount++;
  198. executorStats.verify(threadPoolExecutor);
  199. //****************************************//
  200. }
  201. private static final class ExecutorStats {
  202. public int activeCount = 0;
  203. public int completedTaskCount = 0;
  204. public int corePoolSize = 0;
  205. public int largestPoolSize = 0;
  206. public int poolSize = 0;
  207. public void verify(ThreadPoolExecutor executor) {
  208. assertEquals("Active Thread Counts don't match", activeCount, executor.getActiveCount());
  209. assertEquals("Completed Task Counts don't match", completedTaskCount, executor.getCompletedTaskCount());
  210. assertEquals("Core Pool Sizes don't match", corePoolSize, executor.getCorePoolSize());
  211. assertEquals("Pool Sizes don't match", poolSize, executor.getPoolSize());
  212. assertEquals("Largest Pool Sizes don't match", largestPoolSize, executor.getLargestPoolSize());
  213. }
  214. }
  215. private static final class LatchFutureTask extends FutureTask<Object> {
  216. private final LatchRunnable latchRunnable;
  217. public static LatchFutureTask create() {
  218. return new LatchFutureTask(new LatchRunnable());
  219. }
  220. private LatchFutureTask(LatchRunnable latchRunnable) {
  221. super(latchRunnable, null);
  222. this.latchRunnable = latchRunnable;
  223. }
  224. public void waitForStart() throws InterruptedException {
  225. latchRunnable.waitForStart();
  226. }
  227. public void waitForDone() throws InterruptedException, ExecutionException {
  228. latchRunnable.waitForDone();
  229. this.get();
  230. }
  231. public void done() {
  232. latchRunnable.done();
  233. }
  234. }
  235. private static final class LatchRunnable implements Runnable {
  236. public final CountDownLatch startLatch = new CountDownLatch(1);
  237. public final CountDownLatch stopLatch = new CountDownLatch(1);
  238. public final CountDownLatch doneLatch = new CountDownLatch(1);
  239. public void waitForStart() throws InterruptedException {
  240. startLatch.await();
  241. }
  242. public void waitForDone() throws InterruptedException {
  243. stopLatch.countDown();
  244. doneLatch.await();
  245. }
  246. public void done() {
  247. doneLatch.countDown();
  248. }
  249. public void run() {
  250. startLatch.countDown();
  251. try {
  252. System.out.println(Thread.currentThread().getName());
  253. stopLatch.await();
  254. }
  255. catch (InterruptedException e) {
  256. throw new RuntimeException(e);
  257. }
  258. }
  259. }
  260. }