/* * Copyright 2002-2009 the original author or authors. * * Licensed 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.springframework.scheduling.concurrent; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; /** * JavaBean that allows for configuring a JDK 1.5 {@link java.util.concurrent.ThreadPoolExecutor} * in bean style (through its "corePoolSize", "maxPoolSize", "keepAliveSeconds", * "queueCapacity" properties) and exposing it as a bean reference of its native * {@link java.util.concurrent.ExecutorService} type. * * <p>For an alternative, you may set up a ThreadPoolExecutor instance directly using * constructor injection, or use a factory method definition that points to the JDK 1.5 * {@link java.util.concurrent.Executors} class. * * <p><b>If you need a timing-based {@link java.util.concurrent.ScheduledExecutorService} * instead, consider {@link ScheduledExecutorFactoryBean}.</b> * @author Juergen Hoeller * @since 3.0 * @see java.util.concurrent.ExecutorService * @see java.util.concurrent.Executors * @see java.util.concurrent.ThreadPoolExecutor */ public class ThreadPoolExecutorFactoryBean extends ExecutorConfigurationSupport implements FactoryBean<ExecutorService>, InitializingBean, DisposableBean { private int corePoolSize = 1; private int maxPoolSize = Integer.MAX_VALUE; private int keepAliveSeconds = 60; private boolean allowCoreThreadTimeOut = false; private int queueCapacity = Integer.MAX_VALUE; private boolean exposeUnconfigurableExecutor = false; private ExecutorService exposedExecutor; /** * Set the ThreadPoolExecutor's core pool size. * Default is 1. * <p><b>This setting can be modified at runtime, for example through JMX.</b> */ public void setCorePoolSize(int corePoolSize) { this.corePoolSize = corePoolSize; } /** * Set the ThreadPoolExecutor's maximum pool size. * Default is <code>Integer.MAX_VALUE</code>. * <p><b>This setting can be modified at runtime, for example through JMX.</b> */ public void setMaxPoolSize(int maxPoolSize) { this.maxPoolSize = maxPoolSize; } /** * Set the ThreadPoolExecutor's keep-alive seconds. * Default is 60. * <p><b>This setting can be modified at runtime, for example through JMX.</b> */ public void setKeepAliveSeconds(int keepAliveSeconds) { this.keepAliveSeconds = keepAliveSeconds; } /** * Specify whether to allow core threads to time out. This enables dynamic * growing and shrinking even in combination with a non-zero queue (since * the max pool size will only grow once the queue is full). * <p>Default is "false". Note that this feature is only available on Java 6 * or above. On Java 5, consider switching to the backport-concurrent * version of ThreadPoolTaskExecutor which also supports this feature. * @see java.util.concurrent.ThreadPoolExecutor#allowCoreThreadTimeOut(boolean) */ public void setAllowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) { this.allowCoreThreadTimeOut = allowCoreThreadTimeOut; } /** * Set the capacity for the ThreadPoolExecutor's BlockingQueue. * Default is <code>Integer.MAX_VALUE</code>. * <p>Any positive value will lead to a LinkedBlockingQueue instance; * any other value will lead to a SynchronousQueue instance. * @see java.util.concurrent.LinkedBlockingQueue * @see java.util.concurrent.SynchronousQueue */ public void setQueueCapacity(int queueCapacity) { this.queueCapacity = queueCapacity; } /** * Specify whether this FactoryBean should expose an unconfigurable * decorator for the created executor. * <p>Default is "false", exposing the raw executor as bean reference. * Switch this flag to "true" to strictly prevent clients from * modifying the executor's configuration. * @see java.util.concurrent.Executors#unconfigurableScheduledExecutorService */ public void setExposeUnconfigurableExecutor(boolean exposeUnconfigurableExecutor) { this.exposeUnconfigurableExecutor = exposeUnconfigurableExecutor; } protected ExecutorService initializeExecutor( ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { BlockingQueue<Runnable> queue = createQueue(this.queueCapacity); ThreadPoolExecutor executor = new ThreadPoolExecutor( this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler); if (this.allowCoreThreadTimeOut) { executor.allowCoreThreadTimeOut(true); } // Wrap executor with an unconfigurable decorator. this.exposedExecutor = (this.exposeUnconfigurableExecutor ? Executors.unconfigurableExecutorService(executor) : executor); return executor; } /** * Create the BlockingQueue to use for the ThreadPoolExecutor. * <p>A LinkedBlockingQueue instance will be created for a positive * capacity value; a SynchronousQueue else. * @param queueCapacity the specified queue capacity * @return the BlockingQueue instance * @see java.util.concurrent.LinkedBlockingQueue * @see java.util.concurrent.SynchronousQueue */ protected BlockingQueue<Runnable> createQueue(int queueCapacity) { if (queueCapacity > 0) { return new LinkedBlockingQueue<Runnable>(queueCapacity); } else { return new SynchronousQueue<Runnable>(); } } public ExecutorService getObject() throws Exception { return this.exposedExecutor; } public Class<? extends ExecutorService> getObjectType() { return (this.exposedExecutor != null ? this.exposedExecutor.getClass() : ExecutorService.class); } public boolean isSingleton() { return true; } }