/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ambari.server.controller.test; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.ambari.server.controller.utilities.BufferedThreadPoolExecutorCompletionService; import org.apache.ambari.server.controller.utilities.ScalingThreadPoolExecutor; import org.junit.Test; import junit.framework.Assert; public class BufferedThreadPoolExecutorCompletionServiceTest { private void longOp() throws InterruptedException { Thread.sleep(700); System.out.println("Completed " + Thread.currentThread()); } /** * Tests that when unbounded queue provided to executor, only * {@link ThreadPoolExecutor#getCorePoolSize()} threads are launched * * @throws InterruptedException */ @Test public void testOnlyCorePoolThreadsLaunchedForUnboundedQueue() throws InterruptedException { int CORE_POOL_SIZE = 2; int MAX_POOL_SIZE = 5; int TASKS_COUNT = 8; LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(); ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, 30000, TimeUnit.MILLISECONDS, queue); BufferedThreadPoolExecutorCompletionService<Runnable> service = new BufferedThreadPoolExecutorCompletionService<>(threadPoolExecutor); for (int tc = 0; tc < TASKS_COUNT; tc++) { service.submit(new Runnable() { @Override public void run() { try { longOp(); } catch (InterruptedException e) { e.printStackTrace(); } } }, null); } // While waiting for tasks completion, check how many threads are being used Thread.sleep(500); Assert.assertEquals(CORE_POOL_SIZE, threadPoolExecutor.getActiveCount()); for (int tc = 0; tc < TASKS_COUNT; tc++) { Future<Runnable> take = service.take(); Assert.assertTrue(take.isDone()); Assert.assertTrue("No more than CORE_POOL_SIZE threads should be launched", threadPoolExecutor.getActiveCount() <= CORE_POOL_SIZE); } threadPoolExecutor.shutdown(); } /** * Tests that when load is more than core-pool-size and less than * max-pool-size, the number of threads scales up. * * @throws InterruptedException */ @Test public void testLessThanMaxPoolSizeThreadsLaunched() throws InterruptedException { int CORE_POOL_SIZE = 2; int MAX_POOL_SIZE = 10; int TASKS_COUNT = 8; LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(CORE_POOL_SIZE); ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, 30000, TimeUnit.MILLISECONDS, queue); BufferedThreadPoolExecutorCompletionService<Runnable> service = new BufferedThreadPoolExecutorCompletionService<>(threadPoolExecutor); for (int tc = 0; tc < TASKS_COUNT; tc++) { service.submit(new Runnable() { @Override public void run() { try { longOp(); } catch (InterruptedException e) { e.printStackTrace(); } } }, null); } // While waiting for tasks completion, check how many threads are being used Thread.sleep(500); Assert.assertEquals(TASKS_COUNT - CORE_POOL_SIZE, threadPoolExecutor.getActiveCount()); for (int tc = 0; tc < TASKS_COUNT; tc++) { Future<Runnable> take = service.take(); Assert.assertTrue(take.isDone()); Assert.assertTrue("No more than TASKS_COUNT threads should be launched", threadPoolExecutor.getActiveCount() <= TASKS_COUNT); } threadPoolExecutor.shutdown(); } /** * Tests that when load is more than max-pool-size, the number of threads * scales up. * * @throws InterruptedException */ @Test public void testMaxPoolSizeThreadsLaunched() throws InterruptedException { int CORE_POOL_SIZE = 2; int MAX_POOL_SIZE = 10; int TASKS_COUNT = 24; LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(CORE_POOL_SIZE); ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, 30000, TimeUnit.MILLISECONDS, queue); BufferedThreadPoolExecutorCompletionService<Runnable> service = new BufferedThreadPoolExecutorCompletionService<>(threadPoolExecutor); for (int tc = 0; tc < TASKS_COUNT; tc++) { service.submit(new Runnable() { @Override public void run() { try { longOp(); } catch (InterruptedException e) { e.printStackTrace(); } } }, null); } // While waiting for tasks completion, check how many threads are being used Thread.sleep(500); Assert.assertEquals(MAX_POOL_SIZE, threadPoolExecutor.getActiveCount()); for (int tc = 0; tc < TASKS_COUNT; tc++) { Future<Runnable> take = service.take(); Assert.assertTrue(take.isDone()); Assert.assertTrue("No more than MAX_POOL_SIZE threads should be launched", threadPoolExecutor.getActiveCount() <= MAX_POOL_SIZE); } threadPoolExecutor.shutdown(); } /** * Tests that when load is more than max-pool-size, the number of threads * scales up. * * @throws InterruptedException */ @Test public void testScalingThreadPoolExecutor() throws InterruptedException { int CORE_POOL_SIZE = 2; int MAX_POOL_SIZE = 10; int TASKS_COUNT = 24; ThreadPoolExecutor threadPoolExecutor = new ScalingThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, 30000, TimeUnit.MILLISECONDS, CORE_POOL_SIZE); BufferedThreadPoolExecutorCompletionService<Runnable> service = new BufferedThreadPoolExecutorCompletionService<>(threadPoolExecutor); for (int tc = 0; tc < TASKS_COUNT; tc++) { service.submit(new Runnable() { @Override public void run() { try { longOp(); } catch (InterruptedException e) { e.printStackTrace(); } } }, null); } // While waiting for tasks completion, check how many threads are being used Thread.sleep(500); Assert.assertEquals(MAX_POOL_SIZE, threadPoolExecutor.getActiveCount()); for (int tc = 0; tc < TASKS_COUNT; tc++) { Future<Runnable> take = service.take(); Assert.assertTrue(take.isDone()); Assert.assertTrue("No more than MAX_POOL_SIZE threads should be launched", threadPoolExecutor.getActiveCount() <= MAX_POOL_SIZE); } threadPoolExecutor.shutdown(); } }