Home | History | Annotate | Download | only in concurrent
      1 /*
      2  * Written by Doug Lea with assistance from members of JCP JSR-166
      3  * Expert Group and released to the public domain, as explained at
      4  * http://creativecommons.org/publicdomain/zero/1.0/
      5  */
      6 
      7 /*
      8  * Source:
      9  * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/extra/AtomicDoubleArray.java?revision=1.5
     10  * (Modified to adapt to guava coding conventions and
     11  * to use AtomicLongArray instead of sun.misc.Unsafe)
     12  */
     13 
     14 package com.google.common.util.concurrent;
     15 
     16 import com.google.common.annotations.Beta;
     17 
     18 import static java.lang.Double.doubleToRawLongBits;
     19 import static java.lang.Double.longBitsToDouble;
     20 import java.util.concurrent.atomic.AtomicLongArray;
     21 
     22 /**
     23  * A {@code double} array in which elements may be updated atomically.
     24  * See the {@link java.util.concurrent.atomic} package specification
     25  * for description of the properties of atomic variables.
     26  *
     27  * <p><a name="bitEquals">This class compares primitive {@code double}
     28  * values in methods such as {@link #compareAndSet} by comparing their
     29  * bitwise representation using {@link Double#doubleToRawLongBits},
     30  * which differs from both the primitive double {@code ==} operator
     31  * and from {@link Double#equals}, as if implemented by:
     32  *  <pre> {@code
     33  * static boolean bitEquals(double x, double y) {
     34  *   long xBits = Double.doubleToRawLongBits(x);
     35  *   long yBits = Double.doubleToRawLongBits(y);
     36  *   return xBits == yBits;
     37  * }}</pre>
     38  *
     39  * @author Doug Lea
     40  * @author Martin Buchholz
     41  * @since 11.0
     42  */
     43 @Beta
     44 public class AtomicDoubleArray implements java.io.Serializable {
     45   private static final long serialVersionUID = 0L;
     46 
     47   // Making this non-final is the lesser evil according to Effective
     48   // Java 2nd Edition Item 76: Write readObject methods defensively.
     49   private transient AtomicLongArray longs;
     50 
     51   /**
     52    * Creates a new {@code AtomicDoubleArray} of the given length,
     53    * with all elements initially zero.
     54    *
     55    * @param length the length of the array
     56    */
     57   public AtomicDoubleArray(int length) {
     58     this.longs = new AtomicLongArray(length);
     59   }
     60 
     61   /**
     62    * Creates a new {@code AtomicDoubleArray} with the same length
     63    * as, and all elements copied from, the given array.
     64    *
     65    * @param array the array to copy elements from
     66    * @throws NullPointerException if array is null
     67    */
     68   public AtomicDoubleArray(double[] array) {
     69     final int len = array.length;
     70     long[] longArray = new long[len];
     71     for (int i = 0; i < len; i++) {
     72       longArray[i] = doubleToRawLongBits(array[i]);
     73     }
     74     this.longs = new AtomicLongArray(longArray);
     75   }
     76 
     77   /**
     78    * Returns the length of the array.
     79    *
     80    * @return the length of the array
     81    */
     82   public final int length() {
     83     return longs.length();
     84   }
     85 
     86   /**
     87    * Gets the current value at position {@code i}.
     88    *
     89    * @param i the index
     90    * @return the current value
     91    */
     92   public final double get(int i) {
     93     return longBitsToDouble(longs.get(i));
     94   }
     95 
     96   /**
     97    * Sets the element at position {@code i} to the given value.
     98    *
     99    * @param i the index
    100    * @param newValue the new value
    101    */
    102   public final void set(int i, double newValue) {
    103     long next = doubleToRawLongBits(newValue);
    104     longs.set(i, next);
    105   }
    106 
    107   /**
    108    * Eventually sets the element at position {@code i} to the given value.
    109    *
    110    * @param i the index
    111    * @param newValue the new value
    112    */
    113   public final void lazySet(int i, double newValue) {
    114     set(i, newValue);
    115     // TODO(user): replace with code below when jdk5 support is dropped.
    116     // long next = doubleToRawLongBits(newValue);
    117     // longs.lazySet(i, next);
    118   }
    119 
    120   /**
    121    * Atomically sets the element at position {@code i} to the given value
    122    * and returns the old value.
    123    *
    124    * @param i the index
    125    * @param newValue the new value
    126    * @return the previous value
    127    */
    128   public final double getAndSet(int i, double newValue) {
    129     long next = doubleToRawLongBits(newValue);
    130     return longBitsToDouble(longs.getAndSet(i, next));
    131   }
    132 
    133   /**
    134    * Atomically sets the element at position {@code i} to the given
    135    * updated value
    136    * if the current value is <a href="#bitEquals">bitwise equal</a>
    137    * to the expected value.
    138    *
    139    * @param i the index
    140    * @param expect the expected value
    141    * @param update the new value
    142    * @return true if successful. False return indicates that
    143    * the actual value was not equal to the expected value.
    144    */
    145   public final boolean compareAndSet(int i, double expect, double update) {
    146     return longs.compareAndSet(i,
    147                                doubleToRawLongBits(expect),
    148                                doubleToRawLongBits(update));
    149   }
    150 
    151   /**
    152    * Atomically sets the element at position {@code i} to the given
    153    * updated value
    154    * if the current value is <a href="#bitEquals">bitwise equal</a>
    155    * to the expected value.
    156    *
    157    * <p>May <a
    158    * href="http://download.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html#Spurious">
    159    * fail spuriously</a>
    160    * and does not provide ordering guarantees, so is only rarely an
    161    * appropriate alternative to {@code compareAndSet}.
    162    *
    163    * @param i the index
    164    * @param expect the expected value
    165    * @param update the new value
    166    * @return true if successful
    167    */
    168   public final boolean weakCompareAndSet(int i, double expect, double update) {
    169     return longs.weakCompareAndSet(i,
    170                                    doubleToRawLongBits(expect),
    171                                    doubleToRawLongBits(update));
    172   }
    173 
    174   /**
    175    * Atomically adds the given value to the element at index {@code i}.
    176    *
    177    * @param i the index
    178    * @param delta the value to add
    179    * @return the previous value
    180    */
    181   public final double getAndAdd(int i, double delta) {
    182     while (true) {
    183       long current = longs.get(i);
    184       double currentVal = longBitsToDouble(current);
    185       double nextVal = currentVal + delta;
    186       long next = doubleToRawLongBits(nextVal);
    187       if (longs.compareAndSet(i, current, next)) {
    188         return currentVal;
    189       }
    190     }
    191   }
    192 
    193   /**
    194    * Atomically adds the given value to the element at index {@code i}.
    195    *
    196    * @param i the index
    197    * @param delta the value to add
    198    * @return the updated value
    199    */
    200   public double addAndGet(int i, double delta) {
    201     while (true) {
    202       long current = longs.get(i);
    203       double currentVal = longBitsToDouble(current);
    204       double nextVal = currentVal + delta;
    205       long next = doubleToRawLongBits(nextVal);
    206       if (longs.compareAndSet(i, current, next)) {
    207         return nextVal;
    208       }
    209     }
    210   }
    211 
    212   /**
    213    * Returns the String representation of the current values of array.
    214    * @return the String representation of the current values of array
    215    */
    216   public String toString() {
    217     int iMax = length() - 1;
    218     if (iMax == -1) {
    219       return "[]";
    220     }
    221 
    222     // Double.toString(Math.PI).length() == 17
    223     StringBuilder b = new StringBuilder((17 + 2) * (iMax + 1));
    224     b.append('[');
    225     for (int i = 0;; i++) {
    226       b.append(longBitsToDouble(longs.get(i)));
    227       if (i == iMax) {
    228         return b.append(']').toString();
    229       }
    230       b.append(',').append(' ');
    231     }
    232   }
    233 
    234   /**
    235    * Saves the state to a stream (that is, serializes it).
    236    *
    237    * @serialData The length of the array is emitted (int), followed by all
    238    *             of its elements (each a {@code double}) in the proper order.
    239    */
    240   private void writeObject(java.io.ObjectOutputStream s)
    241       throws java.io.IOException {
    242     s.defaultWriteObject();
    243 
    244     // Write out array length
    245     int length = length();
    246     s.writeInt(length);
    247 
    248     // Write out all elements in the proper order.
    249     for (int i = 0; i < length; i++) {
    250       s.writeDouble(get(i));
    251     }
    252   }
    253 
    254   /**
    255    * Reconstitutes the instance from a stream (that is, deserializes it).
    256    */
    257   private void readObject(java.io.ObjectInputStream s)
    258       throws java.io.IOException, ClassNotFoundException {
    259     s.defaultReadObject();
    260 
    261     // Read in array length and allocate array
    262     int length = s.readInt();
    263     this.longs = new AtomicLongArray(length);
    264 
    265     // Read in all elements in the proper order.
    266     for (int i = 0; i < length; i++) {
    267       set(i, s.readDouble());
    268     }
    269   }
    270 }
    271