All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wamblee.cache.ComputedValue Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2005-2010 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.wamblee.cache;

/**
 * Utility class to deal with recomputation of a certain value. The goal is to
 * have only one thread at a time compute the value while other threads that
 * simulateneously detect recomputation continue with the old value.
 * 
 * 
 * @author Erik Brakkee
 * 
 * @param 
 */
public class ComputedValue {

    /**
     * Computation
     * 
     * @param 
     *            Type of object to compute.
     */
    public static interface Computation {
        /**
         * Checks whether the object is out of date. This will be invoked while
         * holding the lock passed at construction of the compute guard.
         * 
         * Any runtime exceptions thrown are passed back through the
         * {@link ComputedValue#get()}.
         * 
         * @return True iff recomputation is necessary.
         */
        boolean isOutOfDate();

        /**
         * Computes the object. This will be invoked while not holding
         * the lock passed at construction of the compute guard. It is
         * guaranteed that per ComputeGuard, no concurrent calls to compute()
         * are done.
         * 
         * Any runtime exceptions thrown are passed back through the
         * {@link ComputedValue#get()}.
         * 
         * @return Computed object.
         */
        T compute();
    }

    private Object lock;
    private Computation computedValue;

    private Boolean busy;
    private T value;

    /**
     * Constructs the compute guard
     * 
     * @param aLock
     *            Lock to use during computation and to guard the value.
     * @param aComputation
     *            Computation to use.
     */
    public ComputedValue(Object aLock, Computation aComputation) {
        lock = aLock;
        computedValue = aComputation;
        busy = false;
        value = null;
    }

    /**
     * Triggers computation of the value (if no other thread is currently
     * computing the value).
     */
    public void compute() {
        synchronized (this) {
            if (busy) {
                return; // another thread is already taking care of it.
            }
            busy = true;
        }
        try {
            T newvalue = computedValue.compute();
            set(newvalue);
        } finally {
            synchronized (this) {
                busy = false;
            }
        }
    }

    /**
     * Gets the current value of the object, recomputing it if the object is out
     * of date. This method ensures that only one thread at a time will do
     * recomputations.
     * 
     * @return Current value.
     */
    public T get() {
        boolean mustCompute = false;
        synchronized (lock) {
            if (computedValue.isOutOfDate()) {
                mustCompute = true;
            }
        }
        if (mustCompute) {
            compute();
        }
        synchronized (lock) {
            return value;
        }
    }

    /**
     * Gets the currently cached value. No recomputation is performed.
     * 
     * @return Cached value.
     */
    public T getCached() {
        synchronized (lock) {
            return value;
        }

    }

    /**
     * Sets the value explicitly.
     * 
     * @param aValue
     *            value to set.
     */
    public void set(T aValue) {
        synchronized (lock) {
            value = aValue;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy