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