001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.lang3.concurrent;
018
019 import java.util.concurrent.Callable;
020 import java.util.concurrent.ExecutionException;
021 import java.util.concurrent.ExecutorService;
022 import java.util.concurrent.Executors;
023 import java.util.concurrent.Future;
024
025 /**
026 * <p>
027 * A class that allows complex initialization operations in a background task.
028 * </p>
029 * <p>
030 * Applications often have to do some expensive initialization steps when they
031 * are started, e.g. constructing a connection to a database, reading a
032 * configuration file, etc. Doing these things in parallel can enhance
033 * performance as the CPU load can be improved. However, when access to the
034 * resources initialized in a background thread is actually required,
035 * synchronization has to be performed to ensure that their initialization is
036 * complete.
037 * </p>
038 * <p>
039 * This abstract base class provides support for this use case. A concrete
040 * subclass must implement the {@link #initialize()} method. Here an arbitrary
041 * initialization can be implemented, and a result object can be returned. With
042 * this method in place the basic usage of this class is as follows (where
043 * {@code MyBackgroundInitializer} is a concrete subclass):
044 *
045 * <pre>
046 * MyBackgroundInitializer initializer = new MyBackgroundInitializer();
047 * initializer.start();
048 * // Now do some other things. Initialization runs in a parallel thread
049 * ...
050 * // Wait for the end of initialization and access the result object
051 * Object result = initializer.get();
052 * </pre>
053 *
054 * </p>
055 * <p>
056 * After the construction of a {@code BackgroundInitializer} object its
057 * {@link #start()} method has to be called. This starts the background
058 * processing. The application can now continue to do other things. When it
059 * needs access to the object produced by the {@code BackgroundInitializer} it
060 * calls its {@link #get()} method. If initialization is already complete,
061 * {@link #get()} returns the result object immediately. Otherwise it blocks
062 * until the result object is fully constructed.
063 * </p>
064 * <p>
065 * {@code BackgroundInitializer} is a thin wrapper around a {@code Future}
066 * object and uses an {@code ExecutorService} for running the background
067 * initialization task. It is possible to pass in an {@code ExecutorService} at
068 * construction time or set one using {@code setExternalExecutor()} before
069 * {@code start()} was called. Then this object is used to spawn the background
070 * task. If no {@code ExecutorService} has been provided, {@code
071 * BackgroundInitializer} creates a temporary {@code ExecutorService} and
072 * destroys it when initialization is complete.
073 * </p>
074 * <p>
075 * The methods provided by {@code BackgroundInitializer} provide for minimal
076 * interaction with the wrapped {@code Future} object. It is also possible to
077 * obtain the {@code Future} object directly. Then the enhanced functionality
078 * offered by {@code Future} can be used, e.g. to check whether the background
079 * operation is complete or to cancel the operation.
080 * </p>
081 *
082 * @version $Id: BackgroundInitializer.java 929189 2010-03-30 16:49:22Z oheger $
083 * @param <T> the type of the object managed by this initializer class
084 */
085 public abstract class BackgroundInitializer<T> implements
086 ConcurrentInitializer<T> {
087 /** The external executor service for executing tasks. */
088 private ExecutorService externalExecutor;
089
090 /** A reference to the executor service that is actually used. */
091 private ExecutorService executor;
092
093 /** Stores the handle to the background task. */
094 private Future<T> future;
095
096 /**
097 * Creates a new instance of {@code BackgroundInitializer}. No external
098 * {@code ExecutorService} is used.
099 */
100 protected BackgroundInitializer() {
101 this(null);
102 }
103
104 /**
105 * Creates a new instance of {@code BackgroundInitializer} and initializes
106 * it with the given {@code ExecutorService}. If the {@code ExecutorService}
107 * is not null, the background task for initializing this object will be
108 * scheduled at this service. Otherwise a new temporary {@code
109 * ExecutorService} is created.
110 *
111 * @param exec an external {@code ExecutorService} to be used for task
112 * execution
113 */
114 protected BackgroundInitializer(ExecutorService exec) {
115 setExternalExecutor(exec);
116 }
117
118 /**
119 * Returns the external {@code ExecutorService} to be used by this class.
120 *
121 * @return the {@code ExecutorService}
122 */
123 public final synchronized ExecutorService getExternalExecutor() {
124 return externalExecutor;
125 }
126
127 /**
128 * Returns a flag whether this {@code BackgroundInitializer} has already
129 * been started.
130 *
131 * @return a flag whether the {@link #start()} method has already been
132 * called
133 */
134 public synchronized boolean isStarted() {
135 return future != null;
136 }
137
138 /**
139 * Sets an {@code ExecutorService} to be used by this class. The {@code
140 * ExecutorService} passed to this method is used for executing the
141 * background task. Thus it is possible to re-use an already existing
142 * {@code ExecutorService} or to use a specially configured one. If no
143 * {@code ExecutorService} is set, this instance creates a temporary one and
144 * destroys it after background initialization is complete. Note that this
145 * method must be called before {@link #start()}; otherwise an exception is
146 * thrown.
147 *
148 * @param externalExecutor the {@code ExecutorService} to be used
149 * @throws IllegalStateException if this initializer has already been
150 * started
151 */
152 public final synchronized void setExternalExecutor(
153 ExecutorService externalExecutor) {
154 if (isStarted()) {
155 throw new IllegalStateException(
156 "Cannot set ExecutorService after start()!");
157 }
158
159 this.externalExecutor = externalExecutor;
160 }
161
162 /**
163 * Starts the background initialization. With this method the initializer
164 * becomes active and invokes the {@link #initialize()} method in a
165 * background task. A {@code BackgroundInitializer} can be started exactly
166 * once. The return value of this method determines whether the start was
167 * successful: only the first invocation of this method returns <b>true</b>,
168 * following invocations will return <b>false</b>.
169 *
170 * @return a flag whether the initializer could be started successfully
171 */
172 public synchronized boolean start() {
173 // Not yet started?
174 if (!isStarted()) {
175
176 // Determine the executor to use and whether a temporary one has to
177 // be created
178 ExecutorService tempExec;
179 executor = getExternalExecutor();
180 if (executor == null) {
181 executor = tempExec = createExecutor();
182 } else {
183 tempExec = null;
184 }
185
186 future = executor.submit(createTask(tempExec));
187
188 return true;
189 }
190
191 return false;
192 }
193
194 /**
195 * Returns the result of the background initialization. This method blocks
196 * until initialization is complete. If the background processing caused a
197 * runtime exception, it is directly thrown by this method. Checked
198 * exceptions, including {@code InterruptedException} are wrapped in a
199 * {@link ConcurrentException}. Calling this method before {@link #start()}
200 * was called causes an {@code IllegalStateException} exception to be
201 * thrown.
202 *
203 * @return the object produced by this initializer
204 * @throws ConcurrentException if a checked exception occurred during
205 * background processing
206 * @throws IllegalStateException if {@link #start()} has not been called
207 */
208 public T get() throws ConcurrentException {
209 try {
210 return getFuture().get();
211 } catch (ExecutionException execex) {
212 ConcurrentUtils.handleCause(execex);
213 return null; // should not be reached
214 } catch (InterruptedException iex) {
215 // reset interrupted state
216 Thread.currentThread().interrupt();
217 throw new ConcurrentException(iex);
218 }
219 }
220
221 /**
222 * Returns the {@code Future} object that was created when {@link #start()}
223 * was called. Therefore this method can only be called after {@code
224 * start()}.
225 *
226 * @return the {@code Future} object wrapped by this initializer
227 * @throws IllegalStateException if {@link #start()} has not been called
228 */
229 public synchronized Future<T> getFuture() {
230 if (future == null) {
231 throw new IllegalStateException("start() must be called first!");
232 }
233
234 return future;
235 }
236
237 /**
238 * Returns the {@code ExecutorService} that is actually used for executing
239 * the background task. This method can be called after {@link #start()}
240 * (before {@code start()} it returns <b>null</b>). If an external executor
241 * was set, this is also the active executor. Otherwise this method returns
242 * the temporary executor that was created by this object.
243 *
244 * @return the {@code ExecutorService} for executing the background task
245 */
246 protected synchronized final ExecutorService getActiveExecutor() {
247 return executor;
248 }
249
250 /**
251 * Returns the number of background tasks to be created for this
252 * initializer. This information is evaluated when a temporary {@code
253 * ExecutorService} is created. This base implementation returns 1. Derived
254 * classes that do more complex background processing can override it. This
255 * method is called from a synchronized block by the {@link #start()}
256 * method. Therefore overriding methods should be careful with obtaining
257 * other locks and return as fast as possible.
258 *
259 * @return the number of background tasks required by this initializer
260 */
261 protected int getTaskCount() {
262 return 1;
263 }
264
265 /**
266 * Performs the initialization. This method is called in a background task
267 * when this {@code BackgroundInitializer} is started. It must be
268 * implemented by a concrete subclass. An implementation is free to perform
269 * arbitrary initialization. The object returned by this method can be
270 * queried using the {@link #get()} method.
271 *
272 * @return a result object
273 * @throws Exception if an error occurs
274 */
275 protected abstract T initialize() throws Exception;
276
277 /**
278 * Creates a task for the background initialization. The {@code Callable}
279 * object returned by this method is passed to the {@code ExecutorService}.
280 * This implementation returns a task that invokes the {@link #initialize()}
281 * method. If a temporary {@code ExecutorService} is used, it is destroyed
282 * at the end of the task.
283 *
284 * @param execDestroy the {@code ExecutorService} to be destroyed by the
285 * task
286 * @return a task for the background initialization
287 */
288 private Callable<T> createTask(ExecutorService execDestroy) {
289 return new InitializationTask(execDestroy);
290 }
291
292 /**
293 * Creates the {@code ExecutorService} to be used. This method is called if
294 * no {@code ExecutorService} was provided at construction time.
295 *
296 * @return the {@code ExecutorService} to be used
297 */
298 private ExecutorService createExecutor() {
299 return Executors.newFixedThreadPool(getTaskCount());
300 }
301
302 private class InitializationTask implements Callable<T> {
303 /** Stores the executor service to be destroyed at the end. */
304 private final ExecutorService execFinally;
305
306 /**
307 * Creates a new instance of {@code InitializationTask} and initializes
308 * it with the {@code ExecutorService} to be destroyed at the end.
309 *
310 * @param exec the {@code ExecutorService}
311 */
312 public InitializationTask(ExecutorService exec) {
313 execFinally = exec;
314 }
315
316 /**
317 * Initiates initialization and returns the result.
318 *
319 * @return the result object
320 * @throws Exception if an error occurs
321 */
322 public T call() throws Exception {
323 try {
324 return initialize();
325 } finally {
326 if (execFinally != null) {
327 execFinally.shutdown();
328 }
329 }
330 }
331 }
332 }