ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/extra/AtomicDoubleArray.java
Revision: 1.1
Committed: Wed Aug 10 02:03:29 2011 UTC (12 years, 10 months ago) by jsr166
Branch: MAIN
Log Message:
release early; release often

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