Coverage Report - org.apache.commons.lang3.concurrent.AtomicInitializer
 
Classes in this File Line Coverage Branch Coverage Complexity
AtomicInitializer
100%
8/8
100%
4/4
2
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.commons.lang3.concurrent;
 18  
 
 19  
 import java.util.concurrent.atomic.AtomicReference;
 20  
 
 21  
 /**
 22  
  * <p>
 23  
  * A specialized implementation of the {@code ConcurrentInitializer} interface
 24  
  * based on an {@link AtomicReference} variable.
 25  
  * </p>
 26  
  * <p>
 27  
  * This class maintains a member field of type {@code AtomicReference}. It
 28  
  * implements the following algorithm to create and initialize an object in its
 29  
  * {@link #get()} method:
 30  
  * </p>
 31  
  * <ul>
 32  
  * <li>First it is checked whether the {@code AtomicReference} variable contains
 33  
  * already a value. If this is the case, the value is directly returned.</li>
 34  
  * <li>Otherwise the {@link #initialize()} method is called. This method must be
 35  
  * defined in concrete subclasses to actually create the managed object.</li>
 36  
  * <li>After the object was created by {@link #initialize()} it is checked
 37  
  * whether the {@code AtomicReference} variable is still undefined. This has to
 38  
  * be done because in the meantime another thread may have initialized the
 39  
  * object. If the reference is still empty, the newly created object is stored
 40  
  * in it and returned by this method.</li>
 41  
  * <li>Otherwise the value stored in the {@code AtomicReference} is returned.</li>
 42  
  * </ul>
 43  
  * <p>
 44  
  * Because atomic variables are used this class does not need any
 45  
  * synchronization. So there is no danger of deadlock, and access to the managed
 46  
  * object is efficient. However, if multiple threads access the {@code
 47  
  * AtomicInitializer} object before it has been initialized almost at the same
 48  
  * time, it can happen that {@link #initialize()} is called multiple times. The
 49  
  * algorithm outlined above guarantees that {@link #get()} always returns the
 50  
  * same object though.
 51  
  * </p>
 52  
  * <p>
 53  
  * Compared with the {@link LazyInitializer} class, this class can be more
 54  
  * efficient because it does not need synchronization. The drawback is that the
 55  
  * {@link #initialize()} method can be called multiple times which may be
 56  
  * problematic if the creation of the managed object is expensive. As a rule of
 57  
  * thumb this initializer implementation is preferable if there are not too many
 58  
  * threads involved and the probability that multiple threads access an
 59  
  * uninitialized object is small. If there is high parallelism,
 60  
  * {@link LazyInitializer} is more appropriate.
 61  
  * </p>
 62  
  *
 63  
  * @since 3.0
 64  
  * @version $Id: AtomicInitializer.java 1583482 2014-03-31 22:54:57Z niallp $
 65  
  * @param <T> the type of the object managed by this initializer class
 66  
  */
 67  3
 public abstract class AtomicInitializer<T> implements ConcurrentInitializer<T> {
 68  
     /** Holds the reference to the managed object. */
 69  3
     private final AtomicReference<T> reference = new AtomicReference<T>();
 70  
 
 71  
     /**
 72  
      * Returns the object managed by this initializer. The object is created if
 73  
      * it is not available yet and stored internally. This method always returns
 74  
      * the same object.
 75  
      *
 76  
      * @return the object created by this {@code AtomicInitializer}
 77  
      * @throws ConcurrentException if an error occurred during initialization of
 78  
      * the object
 79  
      */
 80  
     @Override
 81  
     public T get() throws ConcurrentException {
 82  33
         T result = reference.get();
 83  
 
 84  33
         if (result == null) {
 85  4
             result = initialize();
 86  4
             if (!reference.compareAndSet(null, result)) {
 87  
                 // another thread has initialized the reference
 88  1
                 result = reference.get();
 89  
             }
 90  
         }
 91  
 
 92  33
         return result;
 93  
     }
 94  
 
 95  
     /**
 96  
      * Creates and initializes the object managed by this {@code
 97  
      * AtomicInitializer}. This method is called by {@link #get()} when the
 98  
      * managed object is not available yet. An implementation can focus on the
 99  
      * creation of the object. No synchronization is needed, as this is already
 100  
      * handled by {@code get()}. As stated by the class comment, it is possible
 101  
      * that this method is called multiple times.
 102  
      *
 103  
      * @return the managed data object
 104  
      * @throws ConcurrentException if an error occurs during object creation
 105  
      */
 106  
     protected abstract T initialize() throws ConcurrentException;
 107  
 }