View Javadoc
1   /*
2    * Copyright 2002-2013 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.scheduling.concurrent;
18  
19  import java.util.concurrent.BlockingQueue;
20  import java.util.concurrent.ExecutorService;
21  import java.util.concurrent.Executors;
22  import java.util.concurrent.LinkedBlockingQueue;
23  import java.util.concurrent.RejectedExecutionHandler;
24  import java.util.concurrent.SynchronousQueue;
25  import java.util.concurrent.ThreadFactory;
26  import java.util.concurrent.ThreadPoolExecutor;
27  import java.util.concurrent.TimeUnit;
28  
29  import org.springframework.beans.factory.DisposableBean;
30  import org.springframework.beans.factory.FactoryBean;
31  import org.springframework.beans.factory.InitializingBean;
32  
33  /**
34   * JavaBean that allows for configuring a {@link java.util.concurrent.ThreadPoolExecutor}
35   * in bean style (through its "corePoolSize", "maxPoolSize", "keepAliveSeconds",
36   * "queueCapacity" properties) and exposing it as a bean reference of its native
37   * {@link java.util.concurrent.ExecutorService} type.
38   *
39   * <p>For an alternative, you may set up a ThreadPoolExecutor instance directly using
40   * constructor injection, or use a factory method definition that points to the
41   * {@link java.util.concurrent.Executors} class.
42   *
43   * <p><b>If you need a timing-based {@link java.util.concurrent.ScheduledExecutorService}
44   * instead, consider {@link ScheduledExecutorFactoryBean}.</b>
45  
46   * @author Juergen Hoeller
47   * @since 3.0
48   * @see java.util.concurrent.ExecutorService
49   * @see java.util.concurrent.Executors
50   * @see java.util.concurrent.ThreadPoolExecutor
51   */
52  @SuppressWarnings("serial")
53  public class ThreadPoolExecutorFactoryBean extends ExecutorConfigurationSupport
54  		implements FactoryBean<ExecutorService>, InitializingBean, DisposableBean {
55  
56  	private int corePoolSize = 1;
57  
58  	private int maxPoolSize = Integer.MAX_VALUE;
59  
60  	private int keepAliveSeconds = 60;
61  
62  	private boolean allowCoreThreadTimeOut = false;
63  
64  	private int queueCapacity = Integer.MAX_VALUE;
65  
66  	private boolean exposeUnconfigurableExecutor = false;
67  
68  	private ExecutorService exposedExecutor;
69  
70  
71  	/**
72  	 * Set the ThreadPoolExecutor's core pool size.
73  	 * Default is 1.
74  	 */
75  	public void setCorePoolSize(int corePoolSize) {
76  		this.corePoolSize = corePoolSize;
77  	}
78  
79  	/**
80  	 * Set the ThreadPoolExecutor's maximum pool size.
81  	 * Default is {@code Integer.MAX_VALUE}.
82  	 */
83  	public void setMaxPoolSize(int maxPoolSize) {
84  		this.maxPoolSize = maxPoolSize;
85  	}
86  
87  	/**
88  	 * Set the ThreadPoolExecutor's keep-alive seconds.
89  	 * Default is 60.
90  	 */
91  	public void setKeepAliveSeconds(int keepAliveSeconds) {
92  		this.keepAliveSeconds = keepAliveSeconds;
93  	}
94  
95  	/**
96  	 * Specify whether to allow core threads to time out. This enables dynamic
97  	 * growing and shrinking even in combination with a non-zero queue (since
98  	 * the max pool size will only grow once the queue is full).
99  	 * <p>Default is "false".
100 	 * @see java.util.concurrent.ThreadPoolExecutor#allowCoreThreadTimeOut(boolean)
101 	 */
102 	public void setAllowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) {
103 		this.allowCoreThreadTimeOut = allowCoreThreadTimeOut;
104 	}
105 
106 	/**
107 	 * Set the capacity for the ThreadPoolExecutor's BlockingQueue.
108 	 * Default is {@code Integer.MAX_VALUE}.
109 	 * <p>Any positive value will lead to a LinkedBlockingQueue instance;
110 	 * any other value will lead to a SynchronousQueue instance.
111 	 * @see java.util.concurrent.LinkedBlockingQueue
112 	 * @see java.util.concurrent.SynchronousQueue
113 	 */
114 	public void setQueueCapacity(int queueCapacity) {
115 		this.queueCapacity = queueCapacity;
116 	}
117 
118 	/**
119 	 * Specify whether this FactoryBean should expose an unconfigurable
120 	 * decorator for the created executor.
121 	 * <p>Default is "false", exposing the raw executor as bean reference.
122 	 * Switch this flag to "true" to strictly prevent clients from
123 	 * modifying the executor's configuration.
124 	 * @see java.util.concurrent.Executors#unconfigurableExecutorService
125 	 */
126 	public void setExposeUnconfigurableExecutor(boolean exposeUnconfigurableExecutor) {
127 		this.exposeUnconfigurableExecutor = exposeUnconfigurableExecutor;
128 	}
129 
130 
131 	@Override
132 	protected ExecutorService initializeExecutor(
133 			ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
134 
135 		BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);
136 		ThreadPoolExecutor executor  = createExecutor(this.corePoolSize, this.maxPoolSize,
137 				this.keepAliveSeconds, queue, threadFactory, rejectedExecutionHandler);
138 		if (this.allowCoreThreadTimeOut) {
139 			executor.allowCoreThreadTimeOut(true);
140 		}
141 
142 		// Wrap executor with an unconfigurable decorator.
143 		this.exposedExecutor = (this.exposeUnconfigurableExecutor ?
144 				Executors.unconfigurableExecutorService(executor) : executor);
145 
146 		return executor;
147 	}
148 
149 	/**
150 	 * Create a new instance of {@link ThreadPoolExecutor} or a subclass thereof.
151 	 * <p>The default implementation creates a standard {@link ThreadPoolExecutor}.
152 	 * Can be overridden to provide custom {@link ThreadPoolExecutor} subclasses.
153 	 * @param corePoolSize the specified core pool size
154 	 * @param maxPoolSize the specified maximum pool size
155 	 * @param keepAliveSeconds the specified keep-alive time in seconds
156 	 * @param queue the BlockingQueue to use
157 	 * @param threadFactory the ThreadFactory to use
158 	 * @param rejectedExecutionHandler the RejectedExecutionHandler to use
159 	 * @return a new ThreadPoolExecutor instance
160 	 * @see #afterPropertiesSet()
161 	 */
162 	protected ThreadPoolExecutor createExecutor(
163 			int corePoolSize, int maxPoolSize, int keepAliveSeconds, BlockingQueue<Runnable> queue,
164 			ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
165 
166 		return new ThreadPoolExecutor(corePoolSize, maxPoolSize,
167 				keepAliveSeconds, TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler);
168 	}
169 
170 	/**
171 	 * Create the BlockingQueue to use for the ThreadPoolExecutor.
172 	 * <p>A LinkedBlockingQueue instance will be created for a positive
173 	 * capacity value; a SynchronousQueue else.
174 	 * @param queueCapacity the specified queue capacity
175 	 * @return the BlockingQueue instance
176 	 * @see java.util.concurrent.LinkedBlockingQueue
177 	 * @see java.util.concurrent.SynchronousQueue
178 	 */
179 	protected BlockingQueue<Runnable> createQueue(int queueCapacity) {
180 		if (queueCapacity > 0) {
181 			return new LinkedBlockingQueue<Runnable>(queueCapacity);
182 		}
183 		else {
184 			return new SynchronousQueue<Runnable>();
185 		}
186 	}
187 
188 
189 	@Override
190 	public ExecutorService getObject() throws Exception {
191 		return this.exposedExecutor;
192 	}
193 
194 	@Override
195 	public Class<? extends ExecutorService> getObjectType() {
196 		return (this.exposedExecutor != null ? this.exposedExecutor.getClass() : ExecutorService.class);
197 	}
198 
199 	@Override
200 	public boolean isSingleton() {
201 		return true;
202 	}
203 
204 }