ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/extra/AtomicDoubleArray.java
Revision: 1.11
Committed: Mon Jul 22 16:47:46 2013 UTC (10 years, 10 months ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Changes since 1.10: +6 -0 lines
Log Message:
fix javadoc warnings for serialization methods

File Contents

# User Rev Content
1 jsr166 1.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     package jsr166e.extra;
8    
9     import static java.lang.Double.doubleToRawLongBits;
10     import static java.lang.Double.longBitsToDouble;
11    
12     /**
13     * A {@code double} array in which elements may be updated atomically.
14     * See the {@link java.util.concurrent.atomic} package specification
15     * for description of the properties of atomic variables.
16     *
17 jsr166 1.8 * <p id="bitEquals">This class compares primitive {@code double}
18 jsr166 1.1 * values in methods such as {@link #compareAndSet} by comparing their
19     * bitwise representation using {@link Double#doubleToRawLongBits},
20     * which differs from both the primitive double {@code ==} operator
21     * and from {@link Double#equals}, as if implemented by:
22     * <pre> {@code
23 jsr166 1.3 * static boolean bitEquals(double x, double y) {
24 jsr166 1.1 * long xBits = Double.doubleToRawLongBits(x);
25     * long yBits = Double.doubleToRawLongBits(y);
26     * return xBits == yBits;
27 jsr166 1.8 * }}</pre>
28 jsr166 1.1 *
29     * @author Doug Lea
30     * @author Martin Buchholz
31     */
32     public class AtomicDoubleArray implements java.io.Serializable {
33     private static final long serialVersionUID = -2308431214976778248L;
34    
35 jsr166 1.4 private final transient long[] array;
36 jsr166 1.1
37     private long checkedByteOffset(int i) {
38     if (i < 0 || i >= array.length)
39     throw new IndexOutOfBoundsException("index " + i);
40    
41     return byteOffset(i);
42     }
43    
44     private static long byteOffset(int i) {
45     return ((long) i << shift) + base;
46     }
47    
48     /**
49     * Creates a new {@code AtomicDoubleArray} of the given length,
50     * with all elements initially zero.
51     *
52     * @param length the length of the array
53     */
54     public AtomicDoubleArray(int length) {
55     array = new long[length];
56     }
57    
58     /**
59     * Creates a new {@code AtomicDoubleArray} with the same length
60     * as, and all elements copied from, the given array.
61     *
62     * @param array the array to copy elements from
63     * @throws NullPointerException if array is null
64     */
65     public AtomicDoubleArray(double[] array) {
66     // Visibility guaranteed by final field guarantees
67     final int len = array.length;
68     final long[] a = new long[len];
69     for (int i = 0; i < len; i++)
70     a[i] = doubleToRawLongBits(array[i]);
71     this.array = a;
72     }
73    
74     /**
75     * Returns the length of the array.
76     *
77     * @return the length of the array
78     */
79     public final int length() {
80     return array.length;
81     }
82    
83     /**
84     * Gets the current value at position {@code i}.
85     *
86     * @param i the index
87     * @return the current value
88     */
89     public final double get(int i) {
90     return longBitsToDouble(getRaw(checkedByteOffset(i)));
91     }
92    
93     private long getRaw(long offset) {
94     return unsafe.getLongVolatile(array, offset);
95     }
96    
97     /**
98     * Sets the element at position {@code i} to the given value.
99     *
100     * @param i the index
101     * @param newValue the new value
102     */
103     public final void set(int i, double newValue) {
104     long next = doubleToRawLongBits(newValue);
105     unsafe.putLongVolatile(array, checkedByteOffset(i), next);
106     }
107    
108     /**
109     * Eventually sets the element at position {@code i} to the given value.
110     *
111     * @param i the index
112     * @param newValue the new value
113     */
114     public final void lazySet(int i, double newValue) {
115     long next = doubleToRawLongBits(newValue);
116     unsafe.putOrderedLong(array, checkedByteOffset(i), next);
117     }
118    
119     /**
120     * Atomically sets the element at position {@code i} to the given value
121     * and returns the old value.
122     *
123     * @param i the index
124     * @param newValue the new value
125     * @return the previous value
126     */
127     public final double getAndSet(int i, double newValue) {
128     long next = doubleToRawLongBits(newValue);
129     long offset = checkedByteOffset(i);
130     while (true) {
131     long current = getRaw(offset);
132     if (compareAndSetRaw(offset, current, next))
133     return longBitsToDouble(current);
134     }
135     }
136    
137     /**
138     * Atomically sets the element at position {@code i} to the given
139     * updated value
140     * if the current value is <a href="#bitEquals">bitwise equal</a>
141     * to the expected value.
142     *
143     * @param i the index
144     * @param expect the expected value
145     * @param update the new value
146     * @return true if successful. False return indicates that
147     * the actual value was not equal to the expected value.
148     */
149     public final boolean compareAndSet(int i, double expect, double update) {
150     return compareAndSetRaw(checkedByteOffset(i),
151     doubleToRawLongBits(expect),
152     doubleToRawLongBits(update));
153     }
154    
155     private boolean compareAndSetRaw(long offset, long expect, long update) {
156     return unsafe.compareAndSwapLong(array, offset, expect, update);
157     }
158    
159     /**
160     * Atomically sets the element at position {@code i} to the given
161     * updated value
162     * if the current value is <a href="#bitEquals">bitwise equal</a>
163     * to the expected value.
164     *
165 jsr166 1.9 * <p><a
166 jsr166 1.2 * href="http://download.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html#Spurious">
167 jsr166 1.9 * May fail spuriously and does not provide ordering guarantees</a>,
168     * so is only rarely an appropriate alternative to {@code compareAndSet}.
169 jsr166 1.1 *
170     * @param i the index
171     * @param expect the expected value
172     * @param update the new value
173     * @return true if successful
174     */
175     public final boolean weakCompareAndSet(int i, double expect, double update) {
176     return compareAndSet(i, expect, update);
177     }
178    
179     /**
180     * Atomically adds the given value to the element at index {@code i}.
181     *
182     * @param i the index
183     * @param delta the value to add
184     * @return the previous value
185     */
186     public final double getAndAdd(int i, double delta) {
187     long offset = checkedByteOffset(i);
188     while (true) {
189     long current = getRaw(offset);
190     double currentVal = longBitsToDouble(current);
191     double nextVal = currentVal + delta;
192     long next = doubleToRawLongBits(nextVal);
193     if (compareAndSetRaw(offset, current, next))
194     return currentVal;
195     }
196     }
197    
198     /**
199     * Atomically adds the given value to the element at index {@code i}.
200     *
201     * @param i the index
202     * @param delta the value to add
203     * @return the updated value
204     */
205     public double addAndGet(int i, double delta) {
206     long offset = checkedByteOffset(i);
207     while (true) {
208     long current = getRaw(offset);
209     double currentVal = longBitsToDouble(current);
210     double nextVal = currentVal + delta;
211     long next = doubleToRawLongBits(nextVal);
212     if (compareAndSetRaw(offset, current, next))
213     return nextVal;
214     }
215     }
216    
217     /**
218     * Returns the String representation of the current values of array.
219     * @return the String representation of the current values of array
220     */
221     public String toString() {
222     int iMax = array.length - 1;
223     if (iMax == -1)
224     return "[]";
225    
226 jsr166 1.2 // Double.toString(Math.PI).length() == 17
227     StringBuilder b = new StringBuilder((17 + 2) * (iMax + 1));
228 jsr166 1.1 b.append('[');
229 jsr166 1.2 for (int i = 0;; i++) {
230 jsr166 1.1 b.append(longBitsToDouble(getRaw(byteOffset(i))));
231     if (i == iMax)
232     return b.append(']').toString();
233     b.append(',').append(' ');
234     }
235     }
236    
237 jsr166 1.4 /**
238     * Saves the state to a stream (that is, serializes it).
239     *
240 jsr166 1.11 * @param s the stream
241     * @throws java.io.IOException if an I/O error occurs
242 jsr166 1.4 * @serialData The length of the array is emitted (int), followed by all
243     * of its elements (each a {@code double}) in the proper order.
244     */
245     private void writeObject(java.io.ObjectOutputStream s)
246 jsr166 1.5 throws java.io.IOException {
247 jsr166 1.4 s.defaultWriteObject();
248    
249     // Write out array length
250     int length = length();
251     s.writeInt(length);
252    
253     // Write out all elements in the proper order.
254     for (int i = 0; i < length; i++)
255     s.writeDouble(get(i));
256     }
257    
258     /**
259     * Reconstitutes the instance from a stream (that is, deserializes it).
260 jsr166 1.11 * @param s the stream
261     * @throws ClassNotFoundException if the class of a serialized object
262     * could not be found
263     * @throws java.io.IOException if an I/O error occurs
264 jsr166 1.4 */
265     private void readObject(java.io.ObjectInputStream s)
266     throws java.io.IOException, ClassNotFoundException {
267     s.defaultReadObject();
268    
269     // Read in array length and allocate array
270     int length = s.readInt();
271     unsafe.putObjectVolatile(this, arrayOffset, new long[length]);
272    
273     // Read in all elements in the proper order.
274     for (int i = 0; i < length; i++)
275     set(i, s.readDouble());
276     }
277    
278 jsr166 1.1 // Unsafe mechanics
279     private static final sun.misc.Unsafe unsafe = getUnsafe();
280 jsr166 1.4 private static final long arrayOffset;
281 jsr166 1.1 private static final int base = unsafe.arrayBaseOffset(long[].class);
282     private static final int shift;
283    
284     static {
285 jsr166 1.4 try {
286     Class<?> k = AtomicDoubleArray.class;
287     arrayOffset = unsafe.objectFieldOffset
288     (k.getDeclaredField("array"));
289     int scale = unsafe.arrayIndexScale(long[].class);
290     if ((scale & (scale - 1)) != 0)
291     throw new Error("data type scale not a power of two");
292     shift = 31 - Integer.numberOfLeadingZeros(scale);
293     } catch (Exception e) {
294     throw new Error(e);
295     }
296 jsr166 1.1 }
297    
298     /**
299     * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package.
300     * Replace with a simple call to Unsafe.getUnsafe when integrating
301     * into a jdk.
302     *
303     * @return a sun.misc.Unsafe
304     */
305     private static sun.misc.Unsafe getUnsafe() {
306     try {
307     return sun.misc.Unsafe.getUnsafe();
308 jsr166 1.6 } catch (SecurityException tryReflectionInstead) {}
309     try {
310     return java.security.AccessController.doPrivileged
311     (new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
312     public sun.misc.Unsafe run() throws Exception {
313     Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
314     for (java.lang.reflect.Field f : k.getDeclaredFields()) {
315     f.setAccessible(true);
316     Object x = f.get(null);
317     if (k.isInstance(x))
318     return k.cast(x);
319     }
320     throw new NoSuchFieldError("the Unsafe");
321     }});
322     } catch (java.security.PrivilegedActionException e) {
323     throw new RuntimeException("Could not initialize intrinsics",
324     e.getCause());
325 jsr166 1.1 }
326     }
327     }