// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.sdk.util;
import java.util.concurrent.atomic.AtomicReference;
/**
* Holds a value yet-to-be-constructed. It gets constructed when method {@link #get()} is
* called the first time. User must provide {@link LazyConstructable.Factory} that
* actually constructs the value. Once the value is constructed, the factory is released
* and may be collected by Java GC.
* <p>Threads: the class is thread-safe; how it's implementation is lock-free, so a
* factory may be called several times from several concurrent threads. However
* method {@link #get()} is guaranteed to always return the same value from to whatever
* thread.
*/
public class LazyConstructable<T> {
public interface Factory<T> {
T construct();
}
public static <T> LazyConstructable<T> create(Factory<T> factory) {
return new LazyConstructable<T>(factory);
}
private final AtomicReference<Result<T>> resultRef;
public LazyConstructable(Factory<T> factory) {
this.resultRef = new AtomicReference<Result<T>>(new FutureResult(factory));
}
/**
* Constructs a value when called first time and returns it to all subsequent calls.
*/
public T get() {
return resultRef.get().get();
}
private static abstract class Result<T> {
abstract T get();
}
private class FutureResult extends Result<T> {
private final Factory<T> factory;
private FutureResult(Factory<T> factory) {
this.factory = factory;
}
@Override
T get() {
T newResult = factory.construct();
resultRef.compareAndSet(this, new ReadyResult<T>(newResult));
return resultRef.get().get();
}
}
private static class ReadyResult<T> extends Result<T> {
private final T result;
public ReadyResult(T result) {
this.result = result;
}
@Override
T get() {
return result;
}
}
}