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

Comparing jsr166/src/test/tck/MapTest.java (file contents):
Revision 1.8 by jsr166, Mon Jul 8 21:18:36 2019 UTC vs.
Revision 1.10 by jsr166, Mon Oct 7 21:06:02 2019 UTC

# Line 5 | Line 5
5   * http://creativecommons.org/publicdomain/zero/1.0/
6   */
7  
8 import junit.framework.Test;
9
8   import java.util.ArrayList;
9   import java.util.Iterator;
10   import java.util.List;
11   import java.util.Map;
12 + import java.util.concurrent.CompletableFuture;
13   import java.util.concurrent.ThreadLocalRandom;
14 + import java.util.concurrent.atomic.AtomicBoolean;
15 + import java.util.concurrent.atomic.AtomicLong;
16 + import java.util.function.BiFunction;
17 +
18 + import junit.framework.Test;
19  
20   /**
21   * Contains tests applicable to all Map implementations.
# Line 200 | Line 204 | public class MapTest extends JSR166TestC
204          assertTrue(clone.isEmpty());
205      }
206  
207 +    /**
208 +     * Concurrent access by compute methods behaves as expected
209 +     */
210 +    public void testConcurrentAccess() throws Throwable {
211 +        final Map map = impl.emptyMap();
212 +        final long testDurationMillis = expensiveTests ? 1000 : 2;
213 +        final int nTasks = impl.isConcurrent()
214 +            ? ThreadLocalRandom.current().nextInt(1, 10)
215 +            : 1;
216 +        final AtomicBoolean done = new AtomicBoolean(false);
217 +        final boolean remappingFunctionCalledAtMostOnce
218 +            = impl.remappingFunctionCalledAtMostOnce();
219 +        final List<CompletableFuture> futures = new ArrayList<>();
220 +        final AtomicLong expectedSum = new AtomicLong(0);
221 +        final Action[] tasks = {
222 +            // repeatedly increment values using compute()
223 +            () -> {
224 +                long[] invocations = new long[2];
225 +                ThreadLocalRandom rnd = ThreadLocalRandom.current();
226 +                BiFunction<Object, Object, Object> incValue = (k, v) -> {
227 +                    invocations[1]++;
228 +                    int vi = (v == null) ? 1 : impl.valueToInt(v) + 1;
229 +                    return impl.makeValue(vi);
230 +                };
231 +                while (!done.getAcquire()) {
232 +                    invocations[0]++;
233 +                    Object key = impl.makeKey(3 * rnd.nextInt(10));
234 +                    map.compute(key, incValue);
235 +                }
236 +                if (remappingFunctionCalledAtMostOnce)
237 +                    assertEquals(invocations[0], invocations[1]);
238 +                expectedSum.getAndAdd(invocations[0]);
239 +            },
240 +            // repeatedly increment values using computeIfPresent()
241 +            () -> {
242 +                long[] invocations = new long[2];
243 +                ThreadLocalRandom rnd = ThreadLocalRandom.current();
244 +                BiFunction<Object, Object, Object> incValue = (k, v) -> {
245 +                    invocations[1]++;
246 +                    int vi = impl.valueToInt(v) + 1;
247 +                    return impl.makeValue(vi);
248 +                };
249 +                while (!done.getAcquire()) {
250 +                    Object key = impl.makeKey(3 * rnd.nextInt(10));
251 +                    if (map.computeIfPresent(key, incValue) != null)
252 +                        invocations[0]++;
253 +                }
254 +                if (remappingFunctionCalledAtMostOnce)
255 +                    assertEquals(invocations[0], invocations[1]);
256 +                expectedSum.getAndAdd(invocations[0]);
257 +            },
258 +        };
259 +        for (int i = nTasks; i--> 0; ) {
260 +            Action task = chooseRandomly(tasks);
261 +            futures.add(CompletableFuture.runAsync(checkedRunnable(task)));
262 +        }
263 +        Thread.sleep(testDurationMillis);
264 +        done.setRelease(true);
265 +        for (var future : futures)
266 +            checkTimedGet(future, null);
267 +
268 +        long sum = map.values().stream().mapToLong(x -> (int) x).sum();
269 +        assertEquals(expectedSum.get(), sum);
270 +    }
271 +
272   //     public void testFailsIntentionallyForDebugging() {
273   //         fail(impl.klazz().getSimpleName());
274   //     }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines