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.atomic.AtomicReference; 020 021/** 022 * <p> 023 * A specialized implementation of the {@code ConcurrentInitializer} interface 024 * based on an {@link AtomicReference} variable. 025 * </p> 026 * <p> 027 * This class maintains a member field of type {@code AtomicReference}. It 028 * implements the following algorithm to create and initialize an object in its 029 * {@link #get()} method: 030 * <ul> 031 * <li>First it is checked whether the {@code AtomicReference} variable contains 032 * already a value. If this is the case, the value is directly returned.</li> 033 * <li>Otherwise the {@link #initialize()} method is called. This method must be 034 * defined in concrete subclasses to actually create the managed object.</li> 035 * <li>After the object was created by {@link #initialize()} it is checked 036 * whether the {@code AtomicReference} variable is still undefined. This has to 037 * be done because in the meantime another thread may have initialized the 038 * object. If the reference is still empty, the newly created object is stored 039 * in it and returned by this method.</li> 040 * <li>Otherwise the value stored in the {@code AtomicReference} is returned.</li> 041 * </ul> 042 * </p> 043 * <p> 044 * Because atomic variables are used this class does not need any 045 * synchronization. So there is no danger of deadlock, and access to the managed 046 * object is efficient. However, if multiple threads access the {@code 047 * AtomicInitializer} object before it has been initialized almost at the same 048 * time, it can happen that {@link #initialize()} is called multiple times. The 049 * algorithm outlined above guarantees that {@link #get()} always returns the 050 * same object though. 051 * </p> 052 * <p> 053 * Compared with the {@link LazyInitializer} class, this class can be more 054 * efficient because it does not need synchronization. The drawback is that the 055 * {@link #initialize()} method can be called multiple times which may be 056 * problematic if the creation of the managed object is expensive. As a rule of 057 * thumb this initializer implementation is preferable if there are not too many 058 * threads involved and the probability that multiple threads access an 059 * uninitialized object is small. If there is high parallelism, 060 * {@link LazyInitializer} is more appropriate. 061 * </p> 062 * 063 * @since 3.0 064 * @version $Id: AtomicInitializer.java 1309977 2012-04-05 17:53:39Z ggregory $ 065 * @param <T> the type of the object managed by this initializer class 066 */ 067public abstract class AtomicInitializer<T> implements ConcurrentInitializer<T> { 068 /** Holds the reference to the managed object. */ 069 private final AtomicReference<T> reference = new AtomicReference<T>(); 070 071 /** 072 * Returns the object managed by this initializer. The object is created if 073 * it is not available yet and stored internally. This method always returns 074 * the same object. 075 * 076 * @return the object created by this {@code AtomicInitializer} 077 * @throws ConcurrentException if an error occurred during initialization of 078 * the object 079 */ 080 @Override 081 public T get() throws ConcurrentException { 082 T result = reference.get(); 083 084 if (result == null) { 085 result = initialize(); 086 if (!reference.compareAndSet(null, result)) { 087 // another thread has initialized the reference 088 result = reference.get(); 089 } 090 } 091 092 return result; 093 } 094 095 /** 096 * Creates and initializes the object managed by this {@code 097 * AtomicInitializer}. This method is called by {@link #get()} when the 098 * managed object is not available yet. An implementation can focus on the 099 * 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}