/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.util; import java.util.concurrent.BlockingQueue; 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; import java.util.concurrent.atomic.AtomicInteger; /** * Simple {@link ThreadPoolExecutor} executor that works around the fact that java 5 can't grow or shrink core threads. * Only java 6 will be able to do that. * * This is a default {@link ThreadPoolExecutor} that has its own {@link ThreadFactory} and has its own {@link BlockingQueue} and {@link RejectedExecutionHandler} instances * for handling the growing from corePoolSize (default running threads) to the maximumPoolSize. * * If you also need scheduling see {@link ServoyScheduledExecutor} * * @author jcompagner * @since 6.0 * */ public class ServoyThreadPoolExecutor extends ThreadPoolExecutor { /** * constructs a thread pool with 1 core thread up to maximumPoolSize that time out after 10 seconds if idle * * @param maximumPoolSize The maximum pool size. * @param name The thread prefix name part. * @param daemonThreads Boolean indicating that the threads should be daemon or not. */ public ServoyThreadPoolExecutor(int maximumPoolSize, String name, boolean daemonThreads) { this(1, maximumPoolSize, 10, TimeUnit.SECONDS, new RejectingLinkedBlockingQueue(), new DefaultThreadFactory(name, daemonThreads), new ReentryRejectedExecutionHandler()); } public ServoyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, String threadName, boolean daemonThreads) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, new RejectingLinkedBlockingQueue(), new DefaultThreadFactory(threadName, daemonThreads), new ReentryRejectedExecutionHandler()); } private ServoyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); ((RejectingLinkedBlockingQueue)workQueue).setExecutor(this); } private static final class ReentryRejectedExecutionHandler implements RejectedExecutionHandler { public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { if (!executor.isShutdown() && !executor.isTerminated() && !executor.isTerminating()) { executor.execute(r); } } } private static class RejectingLinkedBlockingQueue extends LinkedBlockingQueue<Runnable> { private ThreadPoolExecutor executor; public void setExecutor(ThreadPoolExecutor executor) { this.executor = executor; } @Override public boolean offer(Runnable e) { if (executor != null && executor.getPoolSize() < executor.getMaximumPoolSize()) return false; return super.offer(e); } } private static class DefaultThreadFactory implements ThreadFactory { static final AtomicInteger poolNumber = new AtomicInteger(1); final ThreadGroup group; final AtomicInteger threadNumber = new AtomicInteger(1); final String namePrefix; final boolean daemonThreads; @SuppressWarnings("nls") DefaultThreadFactory(String name, boolean daemonThreads) { this.daemonThreads = daemonThreads; SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = (name == null ? "servoy-pool-" : name) + poolNumber.getAndIncrement() + "-thread-"; } public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); t.setDaemon(daemonThreads); if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t; } } }