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