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