jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
changeset 25859 3317bb8137f4
parent 19048 7d0a94c79779
child 32838 caeef2c79243
equal deleted inserted replaced
25858:836adbf7a2cd 25859:3317bb8137f4
       
     1 /*
       
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     3  *
       
     4  * This code is free software; you can redistribute it and/or modify it
       
     5  * under the terms of the GNU General Public License version 2 only, as
       
     6  * published by the Free Software Foundation.  Oracle designates this
       
     7  * particular file as subject to the "Classpath" exception as provided
       
     8  * by Oracle in the LICENSE file that accompanied this code.
       
     9  *
       
    10  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    13  * version 2 for more details (a copy is included in the LICENSE file that
       
    14  * accompanied this code).
       
    15  *
       
    16  * You should have received a copy of the GNU General Public License version
       
    17  * 2 along with this work; if not, write to the Free Software Foundation,
       
    18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    19  *
       
    20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    21  * or visit www.oracle.com if you need additional information or have any
       
    22  * questions.
       
    23  */
       
    24 
       
    25 /*
       
    26  * This file is available under and governed by the GNU General Public
       
    27  * License version 2 only, as published by the Free Software Foundation.
       
    28  * However, the following notice accompanied the original version of this
       
    29  * file:
       
    30  *
       
    31  * Written by Doug Lea with assistance from members of JCP JSR-166
       
    32  * Expert Group and released to the public domain, as explained at
       
    33  * http://creativecommons.org/publicdomain/zero/1.0/
       
    34  */
       
    35 
       
    36 package java.util.concurrent.atomic;
       
    37 import java.util.function.IntUnaryOperator;
       
    38 import java.util.function.IntBinaryOperator;
       
    39 import sun.misc.Unsafe;
       
    40 import java.lang.reflect.Field;
       
    41 import java.lang.reflect.Modifier;
       
    42 import java.security.AccessController;
       
    43 import java.security.PrivilegedExceptionAction;
       
    44 import java.security.PrivilegedActionException;
       
    45 import sun.reflect.CallerSensitive;
       
    46 import sun.reflect.Reflection;
       
    47 
       
    48 /**
       
    49  * A reflection-based utility that enables atomic updates to
       
    50  * designated {@code volatile int} fields of designated classes.
       
    51  * This class is designed for use in atomic data structures in which
       
    52  * several fields of the same node are independently subject to atomic
       
    53  * updates.
       
    54  *
       
    55  * <p>Note that the guarantees of the {@code compareAndSet}
       
    56  * method in this class are weaker than in other atomic classes.
       
    57  * Because this class cannot ensure that all uses of the field
       
    58  * are appropriate for purposes of atomic access, it can
       
    59  * guarantee atomicity only with respect to other invocations of
       
    60  * {@code compareAndSet} and {@code set} on the same updater.
       
    61  *
       
    62  * @since 1.5
       
    63  * @author Doug Lea
       
    64  * @param <T> The type of the object holding the updatable field
       
    65  */
       
    66 public abstract class AtomicIntegerFieldUpdater<T> {
       
    67     /**
       
    68      * Creates and returns an updater for objects with the given field.
       
    69      * The Class argument is needed to check that reflective types and
       
    70      * generic types match.
       
    71      *
       
    72      * @param tclass the class of the objects holding the field
       
    73      * @param fieldName the name of the field to be updated
       
    74      * @param <U> the type of instances of tclass
       
    75      * @return the updater
       
    76      * @throws IllegalArgumentException if the field is not a
       
    77      * volatile integer type
       
    78      * @throws RuntimeException with a nested reflection-based
       
    79      * exception if the class does not hold field or is the wrong type,
       
    80      * or the field is inaccessible to the caller according to Java language
       
    81      * access control
       
    82      */
       
    83     @CallerSensitive
       
    84     public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass,
       
    85                                                               String fieldName) {
       
    86         return new AtomicIntegerFieldUpdaterImpl<U>
       
    87             (tclass, fieldName, Reflection.getCallerClass());
       
    88     }
       
    89 
       
    90     /**
       
    91      * Protected do-nothing constructor for use by subclasses.
       
    92      */
       
    93     protected AtomicIntegerFieldUpdater() {
       
    94     }
       
    95 
       
    96     /**
       
    97      * Atomically sets the field of the given object managed by this updater
       
    98      * to the given updated value if the current value {@code ==} the
       
    99      * expected value. This method is guaranteed to be atomic with respect to
       
   100      * other calls to {@code compareAndSet} and {@code set}, but not
       
   101      * necessarily with respect to other changes in the field.
       
   102      *
       
   103      * @param obj An object whose field to conditionally set
       
   104      * @param expect the expected value
       
   105      * @param update the new value
       
   106      * @return {@code true} if successful
       
   107      * @throws ClassCastException if {@code obj} is not an instance
       
   108      * of the class possessing the field established in the constructor
       
   109      */
       
   110     public abstract boolean compareAndSet(T obj, int expect, int update);
       
   111 
       
   112     /**
       
   113      * Atomically sets the field of the given object managed by this updater
       
   114      * to the given updated value if the current value {@code ==} the
       
   115      * expected value. This method is guaranteed to be atomic with respect to
       
   116      * other calls to {@code compareAndSet} and {@code set}, but not
       
   117      * necessarily with respect to other changes in the field.
       
   118      *
       
   119      * <p><a href="package-summary.html#weakCompareAndSet">May fail
       
   120      * spuriously and does not provide ordering guarantees</a>, so is
       
   121      * only rarely an appropriate alternative to {@code compareAndSet}.
       
   122      *
       
   123      * @param obj An object whose field to conditionally set
       
   124      * @param expect the expected value
       
   125      * @param update the new value
       
   126      * @return {@code true} if successful
       
   127      * @throws ClassCastException if {@code obj} is not an instance
       
   128      * of the class possessing the field established in the constructor
       
   129      */
       
   130     public abstract boolean weakCompareAndSet(T obj, int expect, int update);
       
   131 
       
   132     /**
       
   133      * Sets the field of the given object managed by this updater to the
       
   134      * given updated value. This operation is guaranteed to act as a volatile
       
   135      * store with respect to subsequent invocations of {@code compareAndSet}.
       
   136      *
       
   137      * @param obj An object whose field to set
       
   138      * @param newValue the new value
       
   139      */
       
   140     public abstract void set(T obj, int newValue);
       
   141 
       
   142     /**
       
   143      * Eventually sets the field of the given object managed by this
       
   144      * updater to the given updated value.
       
   145      *
       
   146      * @param obj An object whose field to set
       
   147      * @param newValue the new value
       
   148      * @since 1.6
       
   149      */
       
   150     public abstract void lazySet(T obj, int newValue);
       
   151 
       
   152     /**
       
   153      * Gets the current value held in the field of the given object managed
       
   154      * by this updater.
       
   155      *
       
   156      * @param obj An object whose field to get
       
   157      * @return the current value
       
   158      */
       
   159     public abstract int get(T obj);
       
   160 
       
   161     /**
       
   162      * Atomically sets the field of the given object managed by this updater
       
   163      * to the given value and returns the old value.
       
   164      *
       
   165      * @param obj An object whose field to get and set
       
   166      * @param newValue the new value
       
   167      * @return the previous value
       
   168      */
       
   169     public int getAndSet(T obj, int newValue) {
       
   170         int prev;
       
   171         do {
       
   172             prev = get(obj);
       
   173         } while (!compareAndSet(obj, prev, newValue));
       
   174         return prev;
       
   175     }
       
   176 
       
   177     /**
       
   178      * Atomically increments by one the current value of the field of the
       
   179      * given object managed by this updater.
       
   180      *
       
   181      * @param obj An object whose field to get and set
       
   182      * @return the previous value
       
   183      */
       
   184     public int getAndIncrement(T obj) {
       
   185         int prev, next;
       
   186         do {
       
   187             prev = get(obj);
       
   188             next = prev + 1;
       
   189         } while (!compareAndSet(obj, prev, next));
       
   190         return prev;
       
   191     }
       
   192 
       
   193     /**
       
   194      * Atomically decrements by one the current value of the field of the
       
   195      * given object managed by this updater.
       
   196      *
       
   197      * @param obj An object whose field to get and set
       
   198      * @return the previous value
       
   199      */
       
   200     public int getAndDecrement(T obj) {
       
   201         int prev, next;
       
   202         do {
       
   203             prev = get(obj);
       
   204             next = prev - 1;
       
   205         } while (!compareAndSet(obj, prev, next));
       
   206         return prev;
       
   207     }
       
   208 
       
   209     /**
       
   210      * Atomically adds the given value to the current value of the field of
       
   211      * the given object managed by this updater.
       
   212      *
       
   213      * @param obj An object whose field to get and set
       
   214      * @param delta the value to add
       
   215      * @return the previous value
       
   216      */
       
   217     public int getAndAdd(T obj, int delta) {
       
   218         int prev, next;
       
   219         do {
       
   220             prev = get(obj);
       
   221             next = prev + delta;
       
   222         } while (!compareAndSet(obj, prev, next));
       
   223         return prev;
       
   224     }
       
   225 
       
   226     /**
       
   227      * Atomically increments by one the current value of the field of the
       
   228      * given object managed by this updater.
       
   229      *
       
   230      * @param obj An object whose field to get and set
       
   231      * @return the updated value
       
   232      */
       
   233     public int incrementAndGet(T obj) {
       
   234         int prev, next;
       
   235         do {
       
   236             prev = get(obj);
       
   237             next = prev + 1;
       
   238         } while (!compareAndSet(obj, prev, next));
       
   239         return next;
       
   240     }
       
   241 
       
   242     /**
       
   243      * Atomically decrements by one the current value of the field of the
       
   244      * given object managed by this updater.
       
   245      *
       
   246      * @param obj An object whose field to get and set
       
   247      * @return the updated value
       
   248      */
       
   249     public int decrementAndGet(T obj) {
       
   250         int prev, next;
       
   251         do {
       
   252             prev = get(obj);
       
   253             next = prev - 1;
       
   254         } while (!compareAndSet(obj, prev, next));
       
   255         return next;
       
   256     }
       
   257 
       
   258     /**
       
   259      * Atomically adds the given value to the current value of the field of
       
   260      * the given object managed by this updater.
       
   261      *
       
   262      * @param obj An object whose field to get and set
       
   263      * @param delta the value to add
       
   264      * @return the updated value
       
   265      */
       
   266     public int addAndGet(T obj, int delta) {
       
   267         int prev, next;
       
   268         do {
       
   269             prev = get(obj);
       
   270             next = prev + delta;
       
   271         } while (!compareAndSet(obj, prev, next));
       
   272         return next;
       
   273     }
       
   274 
       
   275     /**
       
   276      * Atomically updates the field of the given object managed by this updater
       
   277      * with the results of applying the given function, returning the previous
       
   278      * value. The function should be side-effect-free, since it may be
       
   279      * re-applied when attempted updates fail due to contention among threads.
       
   280      *
       
   281      * @param obj An object whose field to get and set
       
   282      * @param updateFunction a side-effect-free function
       
   283      * @return the previous value
       
   284      * @since 1.8
       
   285      */
       
   286     public final int getAndUpdate(T obj, IntUnaryOperator updateFunction) {
       
   287         int prev, next;
       
   288         do {
       
   289             prev = get(obj);
       
   290             next = updateFunction.applyAsInt(prev);
       
   291         } while (!compareAndSet(obj, prev, next));
       
   292         return prev;
       
   293     }
       
   294 
       
   295     /**
       
   296      * Atomically updates the field of the given object managed by this updater
       
   297      * with the results of applying the given function, returning the updated
       
   298      * value. The function should be side-effect-free, since it may be
       
   299      * re-applied when attempted updates fail due to contention among threads.
       
   300      *
       
   301      * @param obj An object whose field to get and set
       
   302      * @param updateFunction a side-effect-free function
       
   303      * @return the updated value
       
   304      * @since 1.8
       
   305      */
       
   306     public final int updateAndGet(T obj, IntUnaryOperator updateFunction) {
       
   307         int prev, next;
       
   308         do {
       
   309             prev = get(obj);
       
   310             next = updateFunction.applyAsInt(prev);
       
   311         } while (!compareAndSet(obj, prev, next));
       
   312         return next;
       
   313     }
       
   314 
       
   315     /**
       
   316      * Atomically updates the field of the given object managed by this
       
   317      * updater with the results of applying the given function to the
       
   318      * current and given values, returning the previous value. The
       
   319      * function should be side-effect-free, since it may be re-applied
       
   320      * when attempted updates fail due to contention among threads.  The
       
   321      * function is applied with the current value as its first argument,
       
   322      * and the given update as the second argument.
       
   323      *
       
   324      * @param obj An object whose field to get and set
       
   325      * @param x the update value
       
   326      * @param accumulatorFunction a side-effect-free function of two arguments
       
   327      * @return the previous value
       
   328      * @since 1.8
       
   329      */
       
   330     public final int getAndAccumulate(T obj, int x,
       
   331                                       IntBinaryOperator accumulatorFunction) {
       
   332         int prev, next;
       
   333         do {
       
   334             prev = get(obj);
       
   335             next = accumulatorFunction.applyAsInt(prev, x);
       
   336         } while (!compareAndSet(obj, prev, next));
       
   337         return prev;
       
   338     }
       
   339 
       
   340     /**
       
   341      * Atomically updates the field of the given object managed by this
       
   342      * updater with the results of applying the given function to the
       
   343      * current and given values, returning the updated value. The
       
   344      * function should be side-effect-free, since it may be re-applied
       
   345      * when attempted updates fail due to contention among threads.  The
       
   346      * function is applied with the current value as its first argument,
       
   347      * and the given update as the second argument.
       
   348      *
       
   349      * @param obj An object whose field to get and set
       
   350      * @param x the update value
       
   351      * @param accumulatorFunction a side-effect-free function of two arguments
       
   352      * @return the updated value
       
   353      * @since 1.8
       
   354      */
       
   355     public final int accumulateAndGet(T obj, int x,
       
   356                                       IntBinaryOperator accumulatorFunction) {
       
   357         int prev, next;
       
   358         do {
       
   359             prev = get(obj);
       
   360             next = accumulatorFunction.applyAsInt(prev, x);
       
   361         } while (!compareAndSet(obj, prev, next));
       
   362         return next;
       
   363     }
       
   364 
       
   365     /**
       
   366      * Standard hotspot implementation using intrinsics
       
   367      */
       
   368     private static class AtomicIntegerFieldUpdaterImpl<T>
       
   369             extends AtomicIntegerFieldUpdater<T> {
       
   370         private static final Unsafe unsafe = Unsafe.getUnsafe();
       
   371         private final long offset;
       
   372         private final Class<T> tclass;
       
   373         private final Class<?> cclass;
       
   374 
       
   375         AtomicIntegerFieldUpdaterImpl(final Class<T> tclass,
       
   376                                       final String fieldName,
       
   377                                       final Class<?> caller) {
       
   378             final Field field;
       
   379             final int modifiers;
       
   380             try {
       
   381                 field = AccessController.doPrivileged(
       
   382                     new PrivilegedExceptionAction<Field>() {
       
   383                         public Field run() throws NoSuchFieldException {
       
   384                             return tclass.getDeclaredField(fieldName);
       
   385                         }
       
   386                     });
       
   387                 modifiers = field.getModifiers();
       
   388                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
       
   389                     caller, tclass, null, modifiers);
       
   390                 ClassLoader cl = tclass.getClassLoader();
       
   391                 ClassLoader ccl = caller.getClassLoader();
       
   392                 if ((ccl != null) && (ccl != cl) &&
       
   393                     ((cl == null) || !isAncestor(cl, ccl))) {
       
   394                   sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
       
   395                 }
       
   396             } catch (PrivilegedActionException pae) {
       
   397                 throw new RuntimeException(pae.getException());
       
   398             } catch (Exception ex) {
       
   399                 throw new RuntimeException(ex);
       
   400             }
       
   401 
       
   402             Class<?> fieldt = field.getType();
       
   403             if (fieldt != int.class)
       
   404                 throw new IllegalArgumentException("Must be integer type");
       
   405 
       
   406             if (!Modifier.isVolatile(modifiers))
       
   407                 throw new IllegalArgumentException("Must be volatile type");
       
   408 
       
   409             this.cclass = (Modifier.isProtected(modifiers) &&
       
   410                            caller != tclass) ? caller : null;
       
   411             this.tclass = tclass;
       
   412             offset = unsafe.objectFieldOffset(field);
       
   413         }
       
   414 
       
   415         /**
       
   416          * Returns true if the second classloader can be found in the first
       
   417          * classloader's delegation chain.
       
   418          * Equivalent to the inaccessible: first.isAncestor(second).
       
   419          */
       
   420         private static boolean isAncestor(ClassLoader first, ClassLoader second) {
       
   421             ClassLoader acl = first;
       
   422             do {
       
   423                 acl = acl.getParent();
       
   424                 if (second == acl) {
       
   425                     return true;
       
   426                 }
       
   427             } while (acl != null);
       
   428             return false;
       
   429         }
       
   430 
       
   431         private void fullCheck(T obj) {
       
   432             if (!tclass.isInstance(obj))
       
   433                 throw new ClassCastException();
       
   434             if (cclass != null)
       
   435                 ensureProtectedAccess(obj);
       
   436         }
       
   437 
       
   438         public boolean compareAndSet(T obj, int expect, int update) {
       
   439             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
       
   440             return unsafe.compareAndSwapInt(obj, offset, expect, update);
       
   441         }
       
   442 
       
   443         public boolean weakCompareAndSet(T obj, int expect, int update) {
       
   444             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
       
   445             return unsafe.compareAndSwapInt(obj, offset, expect, update);
       
   446         }
       
   447 
       
   448         public void set(T obj, int newValue) {
       
   449             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
       
   450             unsafe.putIntVolatile(obj, offset, newValue);
       
   451         }
       
   452 
       
   453         public void lazySet(T obj, int newValue) {
       
   454             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
       
   455             unsafe.putOrderedInt(obj, offset, newValue);
       
   456         }
       
   457 
       
   458         public final int get(T obj) {
       
   459             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
       
   460             return unsafe.getIntVolatile(obj, offset);
       
   461         }
       
   462 
       
   463         public int getAndSet(T obj, int newValue) {
       
   464             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
       
   465             return unsafe.getAndSetInt(obj, offset, newValue);
       
   466         }
       
   467 
       
   468         public int getAndIncrement(T obj) {
       
   469             return getAndAdd(obj, 1);
       
   470         }
       
   471 
       
   472         public int getAndDecrement(T obj) {
       
   473             return getAndAdd(obj, -1);
       
   474         }
       
   475 
       
   476         public int getAndAdd(T obj, int delta) {
       
   477             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
       
   478             return unsafe.getAndAddInt(obj, offset, delta);
       
   479         }
       
   480 
       
   481         public int incrementAndGet(T obj) {
       
   482             return getAndAdd(obj, 1) + 1;
       
   483         }
       
   484 
       
   485         public int decrementAndGet(T obj) {
       
   486              return getAndAdd(obj, -1) - 1;
       
   487         }
       
   488 
       
   489         public int addAndGet(T obj, int delta) {
       
   490             return getAndAdd(obj, delta) + delta;
       
   491         }
       
   492 
       
   493         private void ensureProtectedAccess(T obj) {
       
   494             if (cclass.isInstance(obj)) {
       
   495                 return;
       
   496             }
       
   497             throw new RuntimeException(
       
   498                 new IllegalAccessException("Class " +
       
   499                     cclass.getName() +
       
   500                     " can not access a protected member of class " +
       
   501                     tclass.getName() +
       
   502                     " using an instance of " +
       
   503                     obj.getClass().getName()
       
   504                 )
       
   505             );
       
   506         }
       
   507     }
       
   508 }