ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/StripedAdder.java
(Generate patch)

Comparing jsr166/src/jsr166e/StripedAdder.java (file contents):
Revision 1.4 by dl, Sat Jul 23 16:32:53 2011 UTC vs.
Revision 1.5 by dl, Sun Jul 24 15:08:21 2011 UTC

# Line 86 | Line 86 | public class StripedAdder implements Ser
86      static final int NCPU = Runtime.getRuntime().availableProcessors();
87  
88      /**
89 +     * The table size set upon first use when default-constructed
90 +     */
91 +    private static final int DEFAULT_ARRAY_SIZE = 8;
92 +
93 +    /**
94       * Padded version of AtomicLong
95       */
96      static final class Adder extends AtomicLong {
# Line 122 | Line 127 | public class StripedAdder implements Ser
127      static final ThreadHashCode threadHashCode = new ThreadHashCode();
128  
129      /**
130 <     * Table of adders. Minimum size 2. Size grows to be at most NCPU.
130 >     * Table of adders. Size is power of two, grows to be at most NCPU.
131       */
132      private transient volatile Adder[] adders;
133  
134      /**
135       * Serves as a lock when resizing and/or creating Adders.  There
136 <     * is no need for a blocking lock: When busy, other threads try
137 <     * other slots.
136 >     * is no need for a blocking lock: Except during initialization
137 >     * races, when busy, other threads try other slots.
138       */
139      private final AtomicInteger mutex;
140  
# Line 149 | Line 154 | public class StripedAdder implements Ser
154       * will concurrently update the sum.
155       */
156      public StripedAdder(int expectedContention) {
157 <        int cap = (expectedContention < NCPU) ? expectedContention : NCPU;
158 <        int size = 2;
159 <        while (size < cap)
160 <            size <<= 1;
157 >        int size;
158 >        if (expectedContention > 0) {
159 >            int cap = (expectedContention < NCPU) ? expectedContention : NCPU;
160 >            size = 1;
161 >            while (size < cap)
162 >                size <<= 1;
163 >        }
164 >        else
165 >            size = 0;
166          Adder[] as = new Adder[size];
167          for (int i = 0; i < size; ++i)
168              as[i] = new Adder(0);
# Line 181 | Line 191 | public class StripedAdder implements Ser
191      private void retryAdd(long x, HashCode hc) {
192          int h = hc.code;
193          final AtomicInteger mutex = this.mutex;
194 <        AtomicInteger lock = null;                     // nonnull when held
195 <        try {
196 <            for (;;) {
197 <                Adder[] as; Adder a; long v; int n, k; // locals for volatiles
198 <                boolean needLock = true;
199 <                if ((as = adders) == null || (n = as.length) < 1) {
200 <                    if (lock != null)                  // default-initialize
201 <                        adders = new Adder[2];
202 <                }
193 <                else if ((a = as[k = h & (n - 1)]) == null) {
194 <                    if (lock != null) {                // attach new adder
195 <                        as[k] = new Adder(x);
196 <                        break;
194 >        for (boolean retried = false; ; retried = true) {
195 >            Adder[] as; Adder a; long v; int n, k; // Locals for volatiles
196 >            if ((as = adders) == null || (n = as.length) < 1) {
197 >                if (mutex.get() == 0 && mutex.compareAndSet(0, 1)) {
198 >                    try {
199 >                        if (adders == null)        // Default-initialize
200 >                            adders = new Adder[DEFAULT_ARRAY_SIZE];
201 >                    } finally {
202 >                        mutex.set(0);
203                      }
204                  }
205 <                else if (a.compareAndSet(v = a.get(), v + x))
206 <                    break;
207 <                else if (n >= NCPU)                    // cannot expand
208 <                    needLock = false;
209 <                else if (lock != null)                 // expand table
210 <                    adders = Arrays.copyOf(as, n << 1);
211 <
212 <                if (lock == null) {
213 <                    if (needLock && mutex.get() == 0 &&
214 <                        mutex.compareAndSet(0, 1))
215 <                        lock = mutex;
216 <                    else {                             // try elsewhere
217 <                        h ^= h << 13;                  // Marsaglia XorShift
218 <                        h ^= h >>> 17;
219 <                        h ^= h << 5;
205 >                else
206 >                    Thread.yield();               // initialization race
207 >            }
208 >            else if ((a = as[k = h & (n - 1)]) != null &&
209 >                     retried && a.compareAndSet(v = a.get(), v + x))
210 >                break;
211 >            else if ((a == null || n < NCPU) &&
212 >                     mutex.get() == 0 && mutex.compareAndSet(0, 1)) {
213 >                boolean created = false;
214 >                try {
215 >                    if (adders == as) {
216 >                        if (as[k] == null) {
217 >                            as[k] = new Adder(x);
218 >                            created = true;
219 >                        }
220 >                        else {                   // Expand table
221 >                            Adder[] rs = new Adder[n << 1];
222 >                            for (int i = 0; i < n; ++i)
223 >                                rs[i] = as[i];
224 >                            adders = rs;
225 >                        }
226                      }
227 +                } finally {
228 +                    mutex.set(0);
229                  }
230 +                if (created)
231 +                    break;
232 +            }
233 +            else {                                // Try elsewhere
234 +                h ^= h << 13;
235 +                h ^= h >>> 17;                    // Marsaglia XorShift
236 +                h ^= h << 5;
237              }
217        } finally {
218            if (lock != null)
219                lock.set(0);
238          }
239 <        if (hc.code != h)                              // avoid unneeded writes
222 <            hc.code = h;
239 >        hc.code = h;
240      }
241  
242      /**

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines