ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/extra/AtomicDoubleArray.java
Revision: 1.2
Committed: Thu Oct 20 16:33:25 2011 UTC (12 years, 7 months ago) by jsr166
Branch: MAIN
Changes since 1.1: +6 -3 lines
Log Message:
incorporate feedback from guava reviewers; migrate to slightly more guava-compatible coding style

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     * <p><a name="bitEquals">This class compares primitive {@code double}
18     * 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     * boolean bitEquals(double x, double y) {
24     * long xBits = Double.doubleToRawLongBits(x);
25     * long yBits = Double.doubleToRawLongBits(y);
26     * return xBits == yBits;
27     * }}</pre>
28     *
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     private final long[] array;
36    
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.2 * <p>May <a
166     * href="http://download.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html#Spurious">
167     * fail spuriously</a>
168 jsr166 1.1 * and does not provide ordering guarantees, so is only rarely an
169     * appropriate alternative to {@code compareAndSet}.
170     *
171     * @param i the index
172     * @param expect the expected value
173     * @param update the new value
174     * @return true if successful
175     */
176     public final boolean weakCompareAndSet(int i, double expect, double update) {
177     return compareAndSet(i, expect, update);
178     }
179    
180     /**
181     * Atomically adds the given value to the element at index {@code i}.
182     *
183     * @param i the index
184     * @param delta the value to add
185     * @return the previous value
186     */
187     public final double getAndAdd(int i, double delta) {
188     long offset = checkedByteOffset(i);
189     while (true) {
190     long current = getRaw(offset);
191     double currentVal = longBitsToDouble(current);
192     double nextVal = currentVal + delta;
193     long next = doubleToRawLongBits(nextVal);
194     if (compareAndSetRaw(offset, current, next))
195     return currentVal;
196     }
197     }
198    
199     /**
200     * Atomically adds the given value to the element at index {@code i}.
201     *
202     * @param i the index
203     * @param delta the value to add
204     * @return the updated value
205     */
206     public double addAndGet(int i, double delta) {
207     long offset = checkedByteOffset(i);
208     while (true) {
209     long current = getRaw(offset);
210     double currentVal = longBitsToDouble(current);
211     double nextVal = currentVal + delta;
212     long next = doubleToRawLongBits(nextVal);
213     if (compareAndSetRaw(offset, current, next))
214     return nextVal;
215     }
216     }
217    
218     /**
219     * Returns the String representation of the current values of array.
220     * @return the String representation of the current values of array
221     */
222     public String toString() {
223     int iMax = array.length - 1;
224     if (iMax == -1)
225     return "[]";
226    
227 jsr166 1.2 // Double.toString(Math.PI).length() == 17
228     StringBuilder b = new StringBuilder((17 + 2) * (iMax + 1));
229 jsr166 1.1 b.append('[');
230 jsr166 1.2 for (int i = 0;; i++) {
231 jsr166 1.1 b.append(longBitsToDouble(getRaw(byteOffset(i))));
232     if (i == iMax)
233     return b.append(']').toString();
234     b.append(',').append(' ');
235     }
236     }
237    
238     // Unsafe mechanics
239     private static final sun.misc.Unsafe unsafe = getUnsafe();
240     private static final int base = unsafe.arrayBaseOffset(long[].class);
241     private static final int shift;
242    
243     static {
244     int scale = unsafe.arrayIndexScale(long[].class);
245     if ((scale & (scale - 1)) != 0)
246     throw new Error("data type scale not a power of two");
247     shift = 31 - Integer.numberOfLeadingZeros(scale);
248     }
249    
250     /**
251     * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package.
252     * Replace with a simple call to Unsafe.getUnsafe when integrating
253     * into a jdk.
254     *
255     * @return a sun.misc.Unsafe
256     */
257     private static sun.misc.Unsafe getUnsafe() {
258     try {
259     return sun.misc.Unsafe.getUnsafe();
260     } catch (SecurityException se) {
261     try {
262     return java.security.AccessController.doPrivileged
263     (new java.security
264     .PrivilegedExceptionAction<sun.misc.Unsafe>() {
265     public sun.misc.Unsafe run() throws Exception {
266     java.lang.reflect.Field f = sun.misc
267     .Unsafe.class.getDeclaredField("theUnsafe");
268     f.setAccessible(true);
269     return (sun.misc.Unsafe) f.get(null);
270     }});
271     } catch (java.security.PrivilegedActionException e) {
272     throw new RuntimeException("Could not initialize intrinsics",
273     e.getCause());
274     }
275     }
276     }
277     }