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 }