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 * </p> 031 * <ul> 032 * <li>First it is checked whether the {@code AtomicReference} variable contains 033 * already a value. If this is the case, the value is directly returned.</li> 034 * <li>Otherwise the {@link #initialize()} method is called. This method must be 035 * defined in concrete subclasses to actually create the managed object.</li> 036 * <li>After the object was created by {@link #initialize()} it is checked 037 * whether the {@code AtomicReference} variable is still undefined. This has to 038 * be done because in the meantime another thread may have initialized the 039 * object. If the reference is still empty, the newly created object is stored 040 * in it and returned by this method.</li> 041 * <li>Otherwise the value stored in the {@code AtomicReference} is returned.</li> 042 * </ul> 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 * @param <T> the type of the object managed by this initializer class 065 */ 066public abstract class AtomicInitializer<T> implements ConcurrentInitializer<T> { 067 /** Holds the reference to the managed object. */ 068 private final AtomicReference<T> reference = new AtomicReference<>(); 069 070 /** 071 * Returns the object managed by this initializer. The object is created if 072 * it is not available yet and stored internally. This method always returns 073 * the same object. 074 * 075 * @return the object created by this {@code AtomicInitializer} 076 * @throws ConcurrentException if an error occurred during initialization of 077 * the object 078 */ 079 @Override 080 public T get() throws ConcurrentException { 081 T result = reference.get(); 082 083 if (result == null) { 084 result = initialize(); 085 if (!reference.compareAndSet(null, result)) { 086 // another thread has initialized the reference 087 result = reference.get(); 088 } 089 } 090 091 return result; 092 } 093 094 /** 095 * Creates and initializes the object managed by this {@code 096 * AtomicInitializer}. This method is called by {@link #get()} when the 097 * managed object is not available yet. An implementation can focus on the 098 * creation of the object. No synchronization is needed, as this is already 099 * handled by {@code get()}. As stated by the class comment, it is possible 100 * that this method is called multiple times. 101 * 102 * @return the managed data object 103 * @throws ConcurrentException if an error occurs during object creation 104 */ 105 protected abstract T initialize() throws ConcurrentException; 106}