/* * Copyright 2015 Groupon, Inc * Copyright 2015 The Billing Project, LLC * * The Billing Project 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.killbill.commons.concurrent; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class TestDynamicThreadPoolExecutorWithLoggingOnExceptions { private BlockingQueue<Runnable> queue; private ThreadPoolExecutor executor; @BeforeMethod(groups = "fast") public void beforeMethod() { final ThreadFactory threadFactory = new ThreadFactory() { @Override public Thread newThread(final Runnable r) { return new Thread(new ThreadGroup("TestThreadGroup"), r, "-test"); } }; final RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() { @Override public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) { } }; queue = new LinkedBlockingQueue<Runnable>(); executor = new DynamicThreadPoolExecutorWithLoggingOnExceptions(1, 3, 1, TimeUnit.MINUTES, queue, threadFactory, rejectedExecutionHandler); //executor = new ThreadPoolExecutor(1, 3, 1, TimeUnit.MINUTES, queue, threadFactory, rejectedExecutionHandler); } @AfterMethod(groups = "fast") public void afterMethod() { } @Test(groups = "fast") public void testPoolWitMaximumPoolSize() throws InterruptedException { final CountDownLatch startSignal = new CountDownLatch(1); final CountDownLatch doneSignal = new CountDownLatch(4); // Should be handled by corePoolSize ( = 1) thread executor.submit(new TestCallable(startSignal, doneSignal)); Assert.assertEquals(queue.size(), 0); // Should spawn two new threads up to maximumPoolSize (= 3) executor.submit(new TestCallable(startSignal, doneSignal)); Assert.assertEquals(queue.size(), 0); executor.submit(new TestCallable(startSignal, doneSignal)); Assert.assertEquals(queue.size(), 0); // Submit a new task, queue should grow to 1 as other threads are busy. executor.submit(new TestCallable(startSignal, doneSignal)); Assert.assertEquals(queue.size(), 1); // Release other threads startSignal.countDown(); // Wait for all threads to complete doneSignal.await(); Assert.assertEquals(queue.size(), 0); } public static class TestCallable implements Callable<Object> { private final CountDownLatch startSignal; private final CountDownLatch doneSignal; public TestCallable(final CountDownLatch startSignal, final CountDownLatch doneSignal) { this.startSignal = startSignal; this.doneSignal = doneSignal; } @Override public Object call() throws Exception { startSignal.await(); doneSignal.countDown(); return null; } } }