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 import org.apache.commons.lang3.function.FailableConsumer; 22 import org.apache.commons.lang3.function.FailableSupplier; 23 24 /** 25 * A specialized {@link ConcurrentInitializer} implementation which is similar 26 * to {@link AtomicInitializer}, but ensures that the {@link #initialize()} 27 * method is called only once. 28 * 29 * <p> 30 * As {@link AtomicInitializer} this class is based on atomic variables, so it 31 * can create an object under concurrent access without synchronization. 32 * However, it implements an additional check to guarantee that the 33 * {@link #initialize()} method which actually creates the object cannot be 34 * called multiple times. 35 * </p> 36 * <p> 37 * Because of this additional check this implementation is slightly less 38 * efficient than {@link AtomicInitializer}, but if the object creation in the 39 * {@code initialize()} method is expensive or if multiple invocations of 40 * {@code initialize()} are problematic, it is the better alternative. 41 * </p> 42 * <p> 43 * From its semantics this class has the same properties as 44 * {@link LazyInitializer}. It is a "save" implementation of the lazy 45 * initializer pattern. Comparing both classes in terms of efficiency is 46 * difficult because which one is faster depends on multiple factors. Because 47 * {@link AtomicSafeInitializer} does not use synchronization at all it probably 48 * outruns {@link LazyInitializer}, at least under low or moderate concurrent 49 * access. Developers should run their own benchmarks on the expected target 50 * platform to decide which implementation is suitable for their specific use 51 * case. 52 * </p> 53 * 54 * @since 3.0 55 * @param <T> the type of the object managed by this initializer class 56 */ 57 public class AtomicSafeInitializer<T> extends AbstractConcurrentInitializer<T, ConcurrentException> { 58 59 /** 60 * Builds a new instance. 61 * 62 * @param <T> the type of the object managed by the initializer. 63 * @param <I> the type of the initializer managed by this builder. 64 * @since 3.14.0 65 */ 66 public static class Builder<I extends AtomicSafeInitializer<T>, T> extends AbstractBuilder<I, T, Builder<I, T>, ConcurrentException> { 67 68 @SuppressWarnings("unchecked") 69 @Override 70 public I get() { 71 return (I) new AtomicSafeInitializer(getInitializer(), getCloser()); 72 } 73 74 } 75 76 private static final Object NO_INIT = new Object(); 77 78 /** 79 * Creates a new builder. 80 * 81 * @param <T> the type of object to build. 82 * @return a new builder. 83 * @since 3.14.0 84 */ 85 public static <T> Builder<AtomicSafeInitializer<T>, T> builder() { 86 return new Builder<>(); 87 } 88 89 /** A guard which ensures that initialize() is called only once. */ 90 private final AtomicReference<AtomicSafeInitializer<T>> factory = new AtomicReference<>(); 91 92 /** Holds the reference to the managed object. */ 93 private final AtomicReference<T> reference = new AtomicReference<>(getNoInit()); 94 95 /** 96 * Constructs a new instance. 97 */ 98 public AtomicSafeInitializer() { 99 // empty 100 } 101 102 /** 103 * Constructs a new instance. 104 * 105 * @param initializer the initializer supplier called by {@link #initialize()}. 106 * @param closer the closer consumer called by {@link #close()}. 107 */ 108 private AtomicSafeInitializer(final FailableSupplier<T, ConcurrentException> initializer, final FailableConsumer<T, ConcurrentException> closer) { 109 super(initializer, closer); 110 } 111 112 /** 113 * Gets (and initialize, if not initialized yet) the required object 114 * 115 * @return lazily initialized object 116 * @throws ConcurrentException if the initialization of the object causes an 117 * exception 118 */ 119 @Override 120 public final T get() throws ConcurrentException { 121 T result; 122 123 while ((result = reference.get()) == getNoInit()) { 124 if (factory.compareAndSet(null, this)) { 125 reference.set(initialize()); 126 } 127 } 128 129 return result; 130 } 131 132 /** Gets the internal no-init object cast for this instance. */ 133 @SuppressWarnings("unchecked") 134 private T getNoInit() { 135 return (T) NO_INIT; 136 } 137 138 /** 139 * {@inheritDoc} 140 */ 141 @Override 142 protected ConcurrentException getTypedException(Exception e) { 143 return new ConcurrentException(e); 144 } 145 146 /** 147 * Tests whether this instance is initialized. Once initialized, always returns true. 148 * 149 * @return whether this instance is initialized. Once initialized, always returns true. 150 * @since 3.14.0 151 */ 152 @Override 153 public boolean isInitialized() { 154 return reference.get() != NO_INIT; 155 } 156 }