rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
branchjdk7-b147
changeset 1776 b208ff5b7dbc
child 1779 9d757281c666
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java	Mon Feb 09 20:31:09 2015 +0100
     1.3 @@ -0,0 +1,304 @@
     1.4 +/*
     1.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.6 + *
     1.7 + * This code is free software; you can redistribute it and/or modify it
     1.8 + * under the terms of the GNU General Public License version 2 only, as
     1.9 + * published by the Free Software Foundation.  Oracle designates this
    1.10 + * particular file as subject to the "Classpath" exception as provided
    1.11 + * by Oracle in the LICENSE file that accompanied this code.
    1.12 + *
    1.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.16 + * version 2 for more details (a copy is included in the LICENSE file that
    1.17 + * accompanied this code).
    1.18 + *
    1.19 + * You should have received a copy of the GNU General Public License version
    1.20 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.22 + *
    1.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.24 + * or visit www.oracle.com if you need additional information or have any
    1.25 + * questions.
    1.26 + */
    1.27 +
    1.28 +/*
    1.29 + * This file is available under and governed by the GNU General Public
    1.30 + * License version 2 only, as published by the Free Software Foundation.
    1.31 + * However, the following notice accompanied the original version of this
    1.32 + * file:
    1.33 + *
    1.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
    1.35 + * Expert Group and released to the public domain, as explained at
    1.36 + * http://creativecommons.org/publicdomain/zero/1.0/
    1.37 + */
    1.38 +
    1.39 +package java.util.concurrent.atomic;
    1.40 +import sun.misc.Unsafe;
    1.41 +import java.lang.reflect.*;
    1.42 +
    1.43 +/**
    1.44 + * A reflection-based utility that enables atomic updates to
    1.45 + * designated {@code volatile} reference fields of designated
    1.46 + * classes.  This class is designed for use in atomic data structures
    1.47 + * in which several reference fields of the same node are
    1.48 + * independently subject to atomic updates. For example, a tree node
    1.49 + * might be declared as
    1.50 + *
    1.51 + *  <pre> {@code
    1.52 + * class Node {
    1.53 + *   private volatile Node left, right;
    1.54 + *
    1.55 + *   private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater =
    1.56 + *     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left");
    1.57 + *   private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
    1.58 + *     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");
    1.59 + *
    1.60 + *   Node getLeft() { return left;  }
    1.61 + *   boolean compareAndSetLeft(Node expect, Node update) {
    1.62 + *     return leftUpdater.compareAndSet(this, expect, update);
    1.63 + *   }
    1.64 + *   // ... and so on
    1.65 + * }}</pre>
    1.66 + *
    1.67 + * <p>Note that the guarantees of the {@code compareAndSet}
    1.68 + * method in this class are weaker than in other atomic classes.
    1.69 + * Because this class cannot ensure that all uses of the field
    1.70 + * are appropriate for purposes of atomic access, it can
    1.71 + * guarantee atomicity only with respect to other invocations of
    1.72 + * {@code compareAndSet} and {@code set} on the same updater.
    1.73 + *
    1.74 + * @since 1.5
    1.75 + * @author Doug Lea
    1.76 + * @param <T> The type of the object holding the updatable field
    1.77 + * @param <V> The type of the field
    1.78 + */
    1.79 +public abstract class AtomicReferenceFieldUpdater<T, V> {
    1.80 +
    1.81 +    /**
    1.82 +     * Creates and returns an updater for objects with the given field.
    1.83 +     * The Class arguments are needed to check that reflective types and
    1.84 +     * generic types match.
    1.85 +     *
    1.86 +     * @param tclass the class of the objects holding the field.
    1.87 +     * @param vclass the class of the field
    1.88 +     * @param fieldName the name of the field to be updated.
    1.89 +     * @return the updater
    1.90 +     * @throws IllegalArgumentException if the field is not a volatile reference type.
    1.91 +     * @throws RuntimeException with a nested reflection-based
    1.92 +     * exception if the class does not hold field or is the wrong type.
    1.93 +     */
    1.94 +    public static <U, W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) {
    1.95 +        return new AtomicReferenceFieldUpdaterImpl<U,W>(tclass,
    1.96 +                                                        vclass,
    1.97 +                                                        fieldName);
    1.98 +    }
    1.99 +
   1.100 +    /**
   1.101 +     * Protected do-nothing constructor for use by subclasses.
   1.102 +     */
   1.103 +    protected AtomicReferenceFieldUpdater() {
   1.104 +    }
   1.105 +
   1.106 +    /**
   1.107 +     * Atomically sets the field of the given object managed by this updater
   1.108 +     * to the given updated value if the current value {@code ==} the
   1.109 +     * expected value. This method is guaranteed to be atomic with respect to
   1.110 +     * other calls to {@code compareAndSet} and {@code set}, but not
   1.111 +     * necessarily with respect to other changes in the field.
   1.112 +     *
   1.113 +     * @param obj An object whose field to conditionally set
   1.114 +     * @param expect the expected value
   1.115 +     * @param update the new value
   1.116 +     * @return true if successful.
   1.117 +     */
   1.118 +    public abstract boolean compareAndSet(T obj, V expect, V update);
   1.119 +
   1.120 +    /**
   1.121 +     * Atomically sets the field of the given object managed by this updater
   1.122 +     * to the given updated value if the current value {@code ==} the
   1.123 +     * expected value. This method is guaranteed to be atomic with respect to
   1.124 +     * other calls to {@code compareAndSet} and {@code set}, but not
   1.125 +     * necessarily with respect to other changes in the field.
   1.126 +     *
   1.127 +     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
   1.128 +     * and does not provide ordering guarantees, so is only rarely an
   1.129 +     * appropriate alternative to {@code compareAndSet}.
   1.130 +     *
   1.131 +     * @param obj An object whose field to conditionally set
   1.132 +     * @param expect the expected value
   1.133 +     * @param update the new value
   1.134 +     * @return true if successful.
   1.135 +     */
   1.136 +    public abstract boolean weakCompareAndSet(T obj, V expect, V update);
   1.137 +
   1.138 +    /**
   1.139 +     * Sets the field of the given object managed by this updater to the
   1.140 +     * given updated value. This operation is guaranteed to act as a volatile
   1.141 +     * store with respect to subsequent invocations of {@code compareAndSet}.
   1.142 +     *
   1.143 +     * @param obj An object whose field to set
   1.144 +     * @param newValue the new value
   1.145 +     */
   1.146 +    public abstract void set(T obj, V newValue);
   1.147 +
   1.148 +    /**
   1.149 +     * Eventually sets the field of the given object managed by this
   1.150 +     * updater to the given updated value.
   1.151 +     *
   1.152 +     * @param obj An object whose field to set
   1.153 +     * @param newValue the new value
   1.154 +     * @since 1.6
   1.155 +     */
   1.156 +    public abstract void lazySet(T obj, V newValue);
   1.157 +
   1.158 +    /**
   1.159 +     * Gets the current value held in the field of the given object managed
   1.160 +     * by this updater.
   1.161 +     *
   1.162 +     * @param obj An object whose field to get
   1.163 +     * @return the current value
   1.164 +     */
   1.165 +    public abstract V get(T obj);
   1.166 +
   1.167 +    /**
   1.168 +     * Atomically sets the field of the given object managed by this updater
   1.169 +     * to the given value and returns the old value.
   1.170 +     *
   1.171 +     * @param obj An object whose field to get and set
   1.172 +     * @param newValue the new value
   1.173 +     * @return the previous value
   1.174 +     */
   1.175 +    public V getAndSet(T obj, V newValue) {
   1.176 +        for (;;) {
   1.177 +            V current = get(obj);
   1.178 +            if (compareAndSet(obj, current, newValue))
   1.179 +                return current;
   1.180 +        }
   1.181 +    }
   1.182 +
   1.183 +    private static final class AtomicReferenceFieldUpdaterImpl<T,V>
   1.184 +        extends AtomicReferenceFieldUpdater<T,V> {
   1.185 +        private static final Unsafe unsafe = Unsafe.getUnsafe();
   1.186 +        private final long offset;
   1.187 +        private final Class<T> tclass;
   1.188 +        private final Class<V> vclass;
   1.189 +        private final Class cclass;
   1.190 +
   1.191 +        /*
   1.192 +         * Internal type checks within all update methods contain
   1.193 +         * internal inlined optimizations checking for the common
   1.194 +         * cases where the class is final (in which case a simple
   1.195 +         * getClass comparison suffices) or is of type Object (in
   1.196 +         * which case no check is needed because all objects are
   1.197 +         * instances of Object). The Object case is handled simply by
   1.198 +         * setting vclass to null in constructor.  The targetCheck and
   1.199 +         * updateCheck methods are invoked when these faster
   1.200 +         * screenings fail.
   1.201 +         */
   1.202 +
   1.203 +        AtomicReferenceFieldUpdaterImpl(Class<T> tclass,
   1.204 +                                        Class<V> vclass,
   1.205 +                                        String fieldName) {
   1.206 +            Field field = null;
   1.207 +            Class fieldClass = null;
   1.208 +            Class caller = null;
   1.209 +            int modifiers = 0;
   1.210 +            try {
   1.211 +                field = tclass.getDeclaredField(fieldName);
   1.212 +                caller = sun.reflect.Reflection.getCallerClass(3);
   1.213 +                modifiers = field.getModifiers();
   1.214 +                sun.reflect.misc.ReflectUtil.ensureMemberAccess(
   1.215 +                    caller, tclass, null, modifiers);
   1.216 +                sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
   1.217 +                fieldClass = field.getType();
   1.218 +            } catch (Exception ex) {
   1.219 +                throw new RuntimeException(ex);
   1.220 +            }
   1.221 +
   1.222 +            if (vclass != fieldClass)
   1.223 +                throw new ClassCastException();
   1.224 +
   1.225 +            if (!Modifier.isVolatile(modifiers))
   1.226 +                throw new IllegalArgumentException("Must be volatile type");
   1.227 +
   1.228 +            this.cclass = (Modifier.isProtected(modifiers) &&
   1.229 +                           caller != tclass) ? caller : null;
   1.230 +            this.tclass = tclass;
   1.231 +            if (vclass == Object.class)
   1.232 +                this.vclass = null;
   1.233 +            else
   1.234 +                this.vclass = vclass;
   1.235 +            offset = unsafe.objectFieldOffset(field);
   1.236 +        }
   1.237 +
   1.238 +        void targetCheck(T obj) {
   1.239 +            if (!tclass.isInstance(obj))
   1.240 +                throw new ClassCastException();
   1.241 +            if (cclass != null)
   1.242 +                ensureProtectedAccess(obj);
   1.243 +        }
   1.244 +
   1.245 +        void updateCheck(T obj, V update) {
   1.246 +            if (!tclass.isInstance(obj) ||
   1.247 +                (update != null && vclass != null && !vclass.isInstance(update)))
   1.248 +                throw new ClassCastException();
   1.249 +            if (cclass != null)
   1.250 +                ensureProtectedAccess(obj);
   1.251 +        }
   1.252 +
   1.253 +        public boolean compareAndSet(T obj, V expect, V update) {
   1.254 +            if (obj == null || obj.getClass() != tclass || cclass != null ||
   1.255 +                (update != null && vclass != null &&
   1.256 +                 vclass != update.getClass()))
   1.257 +                updateCheck(obj, update);
   1.258 +            return unsafe.compareAndSwapObject(obj, offset, expect, update);
   1.259 +        }
   1.260 +
   1.261 +        public boolean weakCompareAndSet(T obj, V expect, V update) {
   1.262 +            // same implementation as strong form for now
   1.263 +            if (obj == null || obj.getClass() != tclass || cclass != null ||
   1.264 +                (update != null && vclass != null &&
   1.265 +                 vclass != update.getClass()))
   1.266 +                updateCheck(obj, update);
   1.267 +            return unsafe.compareAndSwapObject(obj, offset, expect, update);
   1.268 +        }
   1.269 +
   1.270 +        public void set(T obj, V newValue) {
   1.271 +            if (obj == null || obj.getClass() != tclass || cclass != null ||
   1.272 +                (newValue != null && vclass != null &&
   1.273 +                 vclass != newValue.getClass()))
   1.274 +                updateCheck(obj, newValue);
   1.275 +            unsafe.putObjectVolatile(obj, offset, newValue);
   1.276 +        }
   1.277 +
   1.278 +        public void lazySet(T obj, V newValue) {
   1.279 +            if (obj == null || obj.getClass() != tclass || cclass != null ||
   1.280 +                (newValue != null && vclass != null &&
   1.281 +                 vclass != newValue.getClass()))
   1.282 +                updateCheck(obj, newValue);
   1.283 +            unsafe.putOrderedObject(obj, offset, newValue);
   1.284 +        }
   1.285 +
   1.286 +        public V get(T obj) {
   1.287 +            if (obj == null || obj.getClass() != tclass || cclass != null)
   1.288 +                targetCheck(obj);
   1.289 +            return (V)unsafe.getObjectVolatile(obj, offset);
   1.290 +        }
   1.291 +
   1.292 +        private void ensureProtectedAccess(T obj) {
   1.293 +            if (cclass.isInstance(obj)) {
   1.294 +                return;
   1.295 +            }
   1.296 +            throw new RuntimeException(
   1.297 +                new IllegalAccessException("Class " +
   1.298 +                    cclass.getName() +
   1.299 +                    " can not access a protected member of class " +
   1.300 +                    tclass.getName() +
   1.301 +                    " using an instance of " +
   1.302 +                    obj.getClass().getName()
   1.303 +                )
   1.304 +            );
   1.305 +        }
   1.306 +    }
   1.307 +}