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 */ 017package org.apache.commons.lang3.concurrent; 018 019import java.util.concurrent.Callable; 020import java.util.concurrent.ExecutionException; 021import java.util.concurrent.ExecutorService; 022import java.util.concurrent.Executors; 023import java.util.concurrent.Future; 024 025/** 026 * A class that allows complex initialization operations in a background task. 027 * 028 * <p> 029 * Applications often have to do some expensive initialization steps when they 030 * are started, e.g. constructing a connection to a database, reading a 031 * configuration file, etc. Doing these things in parallel can enhance 032 * performance as the CPU load can be improved. However, when access to the 033 * resources initialized in a background thread is actually required, 034 * synchronization has to be performed to ensure that their initialization is 035 * complete. 036 * </p> 037 * <p> 038 * This abstract base class provides support for this use case. A concrete 039 * subclass must implement the {@link #initialize()} method. Here an arbitrary 040 * initialization can be implemented, and a result object can be returned. With 041 * this method in place the basic usage of this class is as follows (where 042 * {@code MyBackgroundInitializer} is a concrete subclass): 043 * </p> 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 * After the construction of a {@link BackgroundInitializer} object its 056 * {@link #start()} method has to be called. This starts the background 057 * processing. The application can now continue to do other things. When it 058 * needs access to the object produced by the {@link BackgroundInitializer} it 059 * calls its {@link #get()} method. If initialization is already complete, 060 * {@link #get()} returns the result object immediately. Otherwise it blocks 061 * until the result object is fully constructed. 062 * </p> 063 * <p> 064 * {@link BackgroundInitializer} is a thin wrapper around a {@link Future} 065 * object and uses an {@link ExecutorService} for running the background 066 * initialization task. It is possible to pass in an {@link ExecutorService} at 067 * construction time or set one using {@code setExternalExecutor()} before 068 * {@code start()} was called. Then this object is used to spawn the background 069 * task. If no {@link ExecutorService} has been provided, {@code 070 * BackgroundInitializer} creates a temporary {@link ExecutorService} and 071 * destroys it when initialization is complete. 072 * </p> 073 * <p> 074 * The methods provided by {@link BackgroundInitializer} provide for minimal 075 * interaction with the wrapped {@link Future} object. It is also possible to 076 * obtain the {@link Future} object directly. Then the enhanced functionality 077 * offered by {@link Future} can be used, e.g. to check whether the background 078 * operation is complete or to cancel the operation. 079 * </p> 080 * 081 * @since 3.0 082 * @param <T> the type of the object managed by this initializer class 083 */ 084public abstract class BackgroundInitializer<T> implements 085 ConcurrentInitializer<T> { 086 /** The external executor service for executing tasks. */ 087 private ExecutorService externalExecutor; // @GuardedBy("this") 088 089 /** A reference to the executor service that is actually used. */ 090 private ExecutorService executor; // @GuardedBy("this") 091 092 /** Stores the handle to the background task. */ 093 private Future<T> future; // @GuardedBy("this") 094 095 /** 096 * Creates a new instance of {@link BackgroundInitializer}. No external 097 * {@link ExecutorService} is used. 098 */ 099 protected BackgroundInitializer() { 100 this(null); 101 } 102 103 /** 104 * Creates a new instance of {@link BackgroundInitializer} and initializes 105 * it with the given {@link ExecutorService}. If the {@link ExecutorService} 106 * is not null, the background task for initializing this object will be 107 * scheduled at this service. Otherwise a new temporary {@code 108 * ExecutorService} is created. 109 * 110 * @param exec an external {@link ExecutorService} to be used for task 111 * execution 112 */ 113 protected BackgroundInitializer(final ExecutorService exec) { 114 setExternalExecutor(exec); 115 } 116 117 /** 118 * Returns the external {@link ExecutorService} to be used by this class. 119 * 120 * @return the {@link ExecutorService} 121 */ 122 public final synchronized ExecutorService getExternalExecutor() { 123 return externalExecutor; 124 } 125 126 /** 127 * Returns a flag whether this {@link BackgroundInitializer} has already 128 * been started. 129 * 130 * @return a flag whether the {@link #start()} method has already been 131 * called 132 */ 133 public synchronized boolean isStarted() { 134 return future != null; 135 } 136 137 /** 138 * Sets an {@link ExecutorService} to be used by this class. The {@code 139 * ExecutorService} passed to this method is used for executing the 140 * background task. Thus it is possible to re-use an already existing 141 * {@link ExecutorService} or to use a specially configured one. If no 142 * {@link ExecutorService} is set, this instance creates a temporary one and 143 * destroys it after background initialization is complete. Note that this 144 * method must be called before {@link #start()}; otherwise an exception is 145 * thrown. 146 * 147 * @param externalExecutor the {@link ExecutorService} to be used 148 * @throws IllegalStateException if this initializer has already been 149 * started 150 */ 151 public final synchronized void setExternalExecutor( 152 final ExecutorService externalExecutor) { 153 if (isStarted()) { 154 throw new IllegalStateException( 155 "Cannot set ExecutorService after start()!"); 156 } 157 158 this.externalExecutor = externalExecutor; 159 } 160 161 /** 162 * Starts the background initialization. With this method the initializer 163 * becomes active and invokes the {@link #initialize()} method in a 164 * background task. A {@link BackgroundInitializer} can be started exactly 165 * once. The return value of this method determines whether the start was 166 * successful: only the first invocation of this method returns <b>true</b>, 167 * following invocations will return <b>false</b>. 168 * 169 * @return a flag whether the initializer could be started successfully 170 */ 171 public synchronized boolean start() { 172 // Not yet started? 173 if (!isStarted()) { 174 175 // Determine the executor to use and whether a temporary one has to 176 // be created 177 final ExecutorService tempExec; 178 executor = getExternalExecutor(); 179 if (executor == null) { 180 executor = tempExec = createExecutor(); 181 } else { 182 tempExec = null; 183 } 184 185 future = executor.submit(createTask(tempExec)); 186 187 return true; 188 } 189 190 return false; 191 } 192 193 /** 194 * Returns the result of the background initialization. This method blocks 195 * until initialization is complete. If the background processing caused a 196 * runtime exception, it is directly thrown by this method. Checked 197 * exceptions, including {@link InterruptedException} are wrapped in a 198 * {@link ConcurrentException}. Calling this method before {@link #start()} 199 * was called causes an {@link IllegalStateException} exception to be 200 * thrown. 201 * 202 * @return the object produced by this initializer 203 * @throws ConcurrentException if a checked exception occurred during 204 * background processing 205 * @throws IllegalStateException if {@link #start()} has not been called 206 */ 207 @Override 208 public T get() throws ConcurrentException { 209 try { 210 return getFuture().get(); 211 } catch (final ExecutionException execex) { 212 ConcurrentUtils.handleCause(execex); 213 return null; // should not be reached 214 } catch (final InterruptedException iex) { 215 // reset interrupted state 216 Thread.currentThread().interrupt(); 217 throw new ConcurrentException(iex); 218 } 219 } 220 221 /** 222 * Returns the {@link 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 {@link 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 {@link 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 {@link ExecutorService} for executing the background task 245 */ 246 protected final synchronized 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 {@link 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 {@link Callable} 279 * object returned by this method is passed to the {@link ExecutorService}. 280 * This implementation returns a task that invokes the {@link #initialize()} 281 * method. If a temporary {@link ExecutorService} is used, it is destroyed 282 * at the end of the task. 283 * 284 * @param execDestroy the {@link ExecutorService} to be destroyed by the 285 * task 286 * @return a task for the background initialization 287 */ 288 private Callable<T> createTask(final ExecutorService execDestroy) { 289 return new InitializationTask(execDestroy); 290 } 291 292 /** 293 * Creates the {@link ExecutorService} to be used. This method is called if 294 * no {@link ExecutorService} was provided at construction time. 295 * 296 * @return the {@link 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 {@link InitializationTask} and initializes 308 * it with the {@link ExecutorService} to be destroyed at the end. 309 * 310 * @param exec the {@link ExecutorService} 311 */ 312 InitializationTask(final 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 @Override 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}