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 * <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 * </p> 045 * 046 * <pre> 047 * MyBackgroundInitializer initializer = new MyBackgroundInitializer(); 048 * initializer.start(); 049 * // Now do some other things. Initialization runs in a parallel thread 050 * ... 051 * // Wait for the end of initialization and access the result object 052 * Object result = initializer.get(); 053 * </pre> 054 * 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 1583482 2014-03-31 22:54:57Z niallp $ 084 * @param <T> the type of the object managed by this initializer class 085 */ 086public abstract class BackgroundInitializer<T> implements 087 ConcurrentInitializer<T> { 088 /** The external executor service for executing tasks. */ 089 private ExecutorService externalExecutor; // @GuardedBy("this") 090 091 /** A reference to the executor service that is actually used. */ 092 private ExecutorService executor; // @GuardedBy("this") 093 094 /** Stores the handle to the background task. */ 095 private Future<T> future; // @GuardedBy("this") 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(final 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 final 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 @Override 210 public T get() throws ConcurrentException { 211 try { 212 return getFuture().get(); 213 } catch (final ExecutionException execex) { 214 ConcurrentUtils.handleCause(execex); 215 return null; // should not be reached 216 } catch (final InterruptedException iex) { 217 // reset interrupted state 218 Thread.currentThread().interrupt(); 219 throw new ConcurrentException(iex); 220 } 221 } 222 223 /** 224 * Returns the {@code Future} object that was created when {@link #start()} 225 * was called. Therefore this method can only be called after {@code 226 * start()}. 227 * 228 * @return the {@code Future} object wrapped by this initializer 229 * @throws IllegalStateException if {@link #start()} has not been called 230 */ 231 public synchronized Future<T> getFuture() { 232 if (future == null) { 233 throw new IllegalStateException("start() must be called first!"); 234 } 235 236 return future; 237 } 238 239 /** 240 * Returns the {@code ExecutorService} that is actually used for executing 241 * the background task. This method can be called after {@link #start()} 242 * (before {@code start()} it returns <b>null</b>). If an external executor 243 * was set, this is also the active executor. Otherwise this method returns 244 * the temporary executor that was created by this object. 245 * 246 * @return the {@code ExecutorService} for executing the background task 247 */ 248 protected synchronized final ExecutorService getActiveExecutor() { 249 return executor; 250 } 251 252 /** 253 * Returns the number of background tasks to be created for this 254 * initializer. This information is evaluated when a temporary {@code 255 * ExecutorService} is created. This base implementation returns 1. Derived 256 * classes that do more complex background processing can override it. This 257 * method is called from a synchronized block by the {@link #start()} 258 * method. Therefore overriding methods should be careful with obtaining 259 * other locks and return as fast as possible. 260 * 261 * @return the number of background tasks required by this initializer 262 */ 263 protected int getTaskCount() { 264 return 1; 265 } 266 267 /** 268 * Performs the initialization. This method is called in a background task 269 * when this {@code BackgroundInitializer} is started. It must be 270 * implemented by a concrete subclass. An implementation is free to perform 271 * arbitrary initialization. The object returned by this method can be 272 * queried using the {@link #get()} method. 273 * 274 * @return a result object 275 * @throws Exception if an error occurs 276 */ 277 protected abstract T initialize() throws Exception; 278 279 /** 280 * Creates a task for the background initialization. The {@code Callable} 281 * object returned by this method is passed to the {@code ExecutorService}. 282 * This implementation returns a task that invokes the {@link #initialize()} 283 * method. If a temporary {@code ExecutorService} is used, it is destroyed 284 * at the end of the task. 285 * 286 * @param execDestroy the {@code ExecutorService} to be destroyed by the 287 * task 288 * @return a task for the background initialization 289 */ 290 private Callable<T> createTask(final ExecutorService execDestroy) { 291 return new InitializationTask(execDestroy); 292 } 293 294 /** 295 * Creates the {@code ExecutorService} to be used. This method is called if 296 * no {@code ExecutorService} was provided at construction time. 297 * 298 * @return the {@code ExecutorService} to be used 299 */ 300 private ExecutorService createExecutor() { 301 return Executors.newFixedThreadPool(getTaskCount()); 302 } 303 304 private class InitializationTask implements Callable<T> { 305 /** Stores the executor service to be destroyed at the end. */ 306 private final ExecutorService execFinally; 307 308 /** 309 * Creates a new instance of {@code InitializationTask} and initializes 310 * it with the {@code ExecutorService} to be destroyed at the end. 311 * 312 * @param exec the {@code ExecutorService} 313 */ 314 public InitializationTask(final ExecutorService exec) { 315 execFinally = exec; 316 } 317 318 /** 319 * Initiates initialization and returns the result. 320 * 321 * @return the result object 322 * @throws Exception if an error occurs 323 */ 324 @Override 325 public T call() throws Exception { 326 try { 327 return initialize(); 328 } finally { 329 if (execFinally != null) { 330 execFinally.shutdown(); 331 } 332 } 333 } 334 } 335}