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.9 by jsr166, Sun Sep 29 20:40:48 2019 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines