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 * @since 3.0
083 * @version $Id: BackgroundInitializer.java 1082044 2011-03-16 04:26:58Z bayard $
084 * @param <T> the type of the object managed by this initializer class
085 */
086 public abstract class BackgroundInitializer<T> implements
087 ConcurrentInitializer<T> {
088 /** The external executor service for executing tasks. */
089 private ExecutorService externalExecutor;
090
091 /** A reference to the executor service that is actually used. */
092 private ExecutorService executor;
093
094 /** Stores the handle to the background task. */
095 private Future<T> future;
096
097 /**
098 * Creates a new instance of {@code BackgroundInitializer}. No external
099 * {@code ExecutorService} is used.
100 */
101 protected BackgroundInitializer() {
102 this(null);
103 }
104
105 /**
106 * Creates a new instance of {@code BackgroundInitializer} and initializes
107 * it with the given {@code ExecutorService}. If the {@code ExecutorService}
108 * is not null, the background task for initializing this object will be
109 * scheduled at this service. Otherwise a new temporary {@code
110 * ExecutorService} is created.
111 *
112 * @param exec an external {@code ExecutorService} to be used for task
113 * execution
114 */
115 protected BackgroundInitializer(ExecutorService exec) {
116 setExternalExecutor(exec);
117 }
118
119 /**
120 * Returns the external {@code ExecutorService} to be used by this class.
121 *
122 * @return the {@code ExecutorService}
123 */
124 public final synchronized ExecutorService getExternalExecutor() {
125 return externalExecutor;
126 }
127
128 /**
129 * Returns a flag whether this {@code BackgroundInitializer} has already
130 * been started.
131 *
132 * @return a flag whether the {@link #start()} method has already been
133 * called
134 */
135 public synchronized boolean isStarted() {
136 return future != null;
137 }
138
139 /**
140 * Sets an {@code ExecutorService} to be used by this class. The {@code
141 * ExecutorService} passed to this method is used for executing the
142 * background task. Thus it is possible to re-use an already existing
143 * {@code ExecutorService} or to use a specially configured one. If no
144 * {@code ExecutorService} is set, this instance creates a temporary one and
145 * destroys it after background initialization is complete. Note that this
146 * method must be called before {@link #start()}; otherwise an exception is
147 * thrown.
148 *
149 * @param externalExecutor the {@code ExecutorService} to be used
150 * @throws IllegalStateException if this initializer has already been
151 * started
152 */
153 public final synchronized void setExternalExecutor(
154 ExecutorService externalExecutor) {
155 if (isStarted()) {
156 throw new IllegalStateException(
157 "Cannot set ExecutorService after start()!");
158 }
159
160 this.externalExecutor = externalExecutor;
161 }
162
163 /**
164 * Starts the background initialization. With this method the initializer
165 * becomes active and invokes the {@link #initialize()} method in a
166 * background task. A {@code BackgroundInitializer} can be started exactly
167 * once. The return value of this method determines whether the start was
168 * successful: only the first invocation of this method returns <b>true</b>,
169 * following invocations will return <b>false</b>.
170 *
171 * @return a flag whether the initializer could be started successfully
172 */
173 public synchronized boolean start() {
174 // Not yet started?
175 if (!isStarted()) {
176
177 // Determine the executor to use and whether a temporary one has to
178 // be created
179 ExecutorService tempExec;
180 executor = getExternalExecutor();
181 if (executor == null) {
182 executor = tempExec = createExecutor();
183 } else {
184 tempExec = null;
185 }
186
187 future = executor.submit(createTask(tempExec));
188
189 return true;
190 }
191
192 return false;
193 }
194
195 /**
196 * Returns the result of the background initialization. This method blocks
197 * until initialization is complete. If the background processing caused a
198 * runtime exception, it is directly thrown by this method. Checked
199 * exceptions, including {@code InterruptedException} are wrapped in a
200 * {@link ConcurrentException}. Calling this method before {@link #start()}
201 * was called causes an {@code IllegalStateException} exception to be
202 * thrown.
203 *
204 * @return the object produced by this initializer
205 * @throws ConcurrentException if a checked exception occurred during
206 * background processing
207 * @throws IllegalStateException if {@link #start()} has not been called
208 */
209 public T get() throws ConcurrentException {
210 try {
211 return getFuture().get();
212 } catch (ExecutionException execex) {
213 ConcurrentUtils.handleCause(execex);
214 return null; // should not be reached
215 } catch (InterruptedException iex) {
216 // reset interrupted state
217 Thread.currentThread().interrupt();
218 throw new ConcurrentException(iex);
219 }
220 }
221
222 /**
223 * Returns the {@code Future} object that was created when {@link #start()}
224 * was called. Therefore this method can only be called after {@code
225 * start()}.
226 *
227 * @return the {@code Future} object wrapped by this initializer
228 * @throws IllegalStateException if {@link #start()} has not been called
229 */
230 public synchronized Future<T> getFuture() {
231 if (future == null) {
232 throw new IllegalStateException("start() must be called first!");
233 }
234
235 return future;
236 }
237
238 /**
239 * Returns the {@code ExecutorService} that is actually used for executing
240 * the background task. This method can be called after {@link #start()}
241 * (before {@code start()} it returns <b>null</b>). If an external executor
242 * was set, this is also the active executor. Otherwise this method returns
243 * the temporary executor that was created by this object.
244 *
245 * @return the {@code ExecutorService} for executing the background task
246 */
247 protected synchronized final ExecutorService getActiveExecutor() {
248 return executor;
249 }
250
251 /**
252 * Returns the number of background tasks to be created for this
253 * initializer. This information is evaluated when a temporary {@code
254 * ExecutorService} is created. This base implementation returns 1. Derived
255 * classes that do more complex background processing can override it. This
256 * method is called from a synchronized block by the {@link #start()}
257 * method. Therefore overriding methods should be careful with obtaining
258 * other locks and return as fast as possible.
259 *
260 * @return the number of background tasks required by this initializer
261 */
262 protected int getTaskCount() {
263 return 1;
264 }
265
266 /**
267 * Performs the initialization. This method is called in a background task
268 * when this {@code BackgroundInitializer} is started. It must be
269 * implemented by a concrete subclass. An implementation is free to perform
270 * arbitrary initialization. The object returned by this method can be
271 * queried using the {@link #get()} method.
272 *
273 * @return a result object
274 * @throws Exception if an error occurs
275 */
276 protected abstract T initialize() throws Exception;
277
278 /**
279 * Creates a task for the background initialization. The {@code Callable}
280 * object returned by this method is passed to the {@code ExecutorService}.
281 * This implementation returns a task that invokes the {@link #initialize()}
282 * method. If a temporary {@code ExecutorService} is used, it is destroyed
283 * at the end of the task.
284 *
285 * @param execDestroy the {@code ExecutorService} to be destroyed by the
286 * task
287 * @return a task for the background initialization
288 */
289 private Callable<T> createTask(ExecutorService execDestroy) {
290 return new InitializationTask(execDestroy);
291 }
292
293 /**
294 * Creates the {@code ExecutorService} to be used. This method is called if
295 * no {@code ExecutorService} was provided at construction time.
296 *
297 * @return the {@code ExecutorService} to be used
298 */
299 private ExecutorService createExecutor() {
300 return Executors.newFixedThreadPool(getTaskCount());
301 }
302
303 private class InitializationTask implements Callable<T> {
304 /** Stores the executor service to be destroyed at the end. */
305 private final ExecutorService execFinally;
306
307 /**
308 * Creates a new instance of {@code InitializationTask} and initializes
309 * it with the {@code ExecutorService} to be destroyed at the end.
310 *
311 * @param exec the {@code ExecutorService}
312 */
313 public InitializationTask(ExecutorService exec) {
314 execFinally = exec;
315 }
316
317 /**
318 * Initiates initialization and returns the result.
319 *
320 * @return the result object
321 * @throws Exception if an error occurs
322 */
323 public T call() throws Exception {
324 try {
325 return initialize();
326 } finally {
327 if (execFinally != null) {
328 execFinally.shutdown();
329 }
330 }
331 }
332 }
333 }