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 021import org.apache.commons.lang3.function.FailableConsumer; 022import org.apache.commons.lang3.function.FailableSupplier; 023 024/** 025 * A specialized {@link ConcurrentInitializer} implementation which is similar 026 * to {@link AtomicInitializer}, but ensures that the {@link #initialize()} 027 * method is called only once. 028 * 029 * <p> 030 * As {@link AtomicInitializer} this class is based on atomic variables, so it 031 * can create an object under concurrent access without synchronization. 032 * However, it implements an additional check to guarantee that the 033 * {@link #initialize()} method which actually creates the object cannot be 034 * called multiple times. 035 * </p> 036 * <p> 037 * Because of this additional check this implementation is slightly less 038 * efficient than {@link AtomicInitializer}, but if the object creation in the 039 * {@code initialize()} method is expensive or if multiple invocations of 040 * {@code initialize()} are problematic, it is the better alternative. 041 * </p> 042 * <p> 043 * From its semantics this class has the same properties as 044 * {@link LazyInitializer}. It is a "save" implementation of the lazy 045 * initializer pattern. Comparing both classes in terms of efficiency is 046 * difficult because which one is faster depends on multiple factors. Because 047 * {@link AtomicSafeInitializer} does not use synchronization at all it probably 048 * outruns {@link LazyInitializer}, at least under low or moderate concurrent 049 * access. Developers should run their own benchmarks on the expected target 050 * platform to decide which implementation is suitable for their specific use 051 * case. 052 * </p> 053 * 054 * @since 3.0 055 * @param <T> the type of the object managed by this initializer class 056 */ 057public class AtomicSafeInitializer<T> extends AbstractConcurrentInitializer<T, ConcurrentException> { 058 059 /** 060 * Builds a new instance. 061 * 062 * @param <T> the type of the object managed by the initializer. 063 * @param <I> the type of the initializer managed by this builder. 064 * @since 3.14.0 065 */ 066 public static class Builder<I extends AtomicSafeInitializer<T>, T> extends AbstractBuilder<I, T, Builder<I, T>, ConcurrentException> { 067 068 /** 069 * Constructs a new instance. 070 */ 071 public Builder() { 072 // empty 073 } 074 075 @SuppressWarnings("unchecked") 076 @Override 077 public I get() { 078 return (I) new AtomicSafeInitializer(getInitializer(), getCloser()); 079 } 080 081 } 082 083 private static final Object NO_INIT = new Object(); 084 085 /** 086 * Creates a new builder. 087 * 088 * @param <T> the type of object to build. 089 * @return a new builder. 090 * @since 3.14.0 091 */ 092 public static <T> Builder<AtomicSafeInitializer<T>, T> builder() { 093 return new Builder<>(); 094 } 095 096 /** A guard which ensures that initialize() is called only once. */ 097 private final AtomicReference<AtomicSafeInitializer<T>> factory = new AtomicReference<>(); 098 099 /** Holds the reference to the managed object. */ 100 private final AtomicReference<T> reference = new AtomicReference<>(getNoInit()); 101 102 /** 103 * Constructs a new instance. 104 */ 105 public AtomicSafeInitializer() { 106 // empty 107 } 108 109 /** 110 * Constructs a new instance. 111 * 112 * @param initializer the initializer supplier called by {@link #initialize()}. 113 * @param closer the closer consumer called by {@link #close()}. 114 */ 115 private AtomicSafeInitializer(final FailableSupplier<T, ConcurrentException> initializer, final FailableConsumer<T, ConcurrentException> closer) { 116 super(initializer, closer); 117 } 118 119 /** 120 * Gets (and initialize, if not initialized yet) the required object 121 * 122 * @return lazily initialized object 123 * @throws ConcurrentException if the initialization of the object causes an 124 * exception 125 */ 126 @Override 127 public final T get() throws ConcurrentException { 128 T result; 129 130 while ((result = reference.get()) == getNoInit()) { 131 if (factory.compareAndSet(null, this)) { 132 reference.set(initialize()); 133 } 134 } 135 136 return result; 137 } 138 139 /** Gets the internal no-init object cast for this instance. */ 140 @SuppressWarnings("unchecked") 141 private T getNoInit() { 142 return (T) NO_INIT; 143 } 144 145 /** 146 * {@inheritDoc} 147 */ 148 @Override 149 protected ConcurrentException getTypedException(final Exception e) { 150 return new ConcurrentException(e); 151 } 152 153 /** 154 * Tests whether this instance is initialized. Once initialized, always returns true. 155 * 156 * @return whether this instance is initialized. Once initialized, always returns true. 157 * @since 3.14.0 158 */ 159 @Override 160 public boolean isInitialized() { 161 return reference.get() != NO_INIT; 162 } 163}