public Mutex mutexFor(Object mutexKey) {
        Mutex mutex;
        synchronized (mainMutex) {
            mutex = mutexMap.computeIfAbsent(mutexKey, Mutex::new);
            mutex.referenceCount++;
        }
        return mutex;
    }
@Test
    public void testConcurrentMutexOperation() {
        final String[] keys = new String[]{"a", "b", "c"};
        final Map<String, Integer> timesAcquired = new HashMap<>();

        int concurrency = RuntimeAvailableProcessors.get() * 3;
        final CyclicBarrier cyc = new CyclicBarrier(concurrency + 1);

        for (int i = 0; i < concurrency; i++) {
            new Thread(() -> {
                await(cyc);

                for (String key : keys) {
                    try (ContextMutexFactory.Mutex mutex = contextMutexFactory.mutexFor(key)) {
                        synchronized (mutex) {
                            Integer value = timesAcquired.get(key);
                            if (value == null) {
                                timesAcquired.put(key, 1);
                            } else {
                                timesAcquired.put(key, value + 1);
                            }
                        }
                    }
                }

                await(cyc);
            }).start();
        }
        // start threads, wait for them to finish
        await(cyc);
        await(cyc);

        // assert each key's lock was acquired by each thread
        for (String key : keys) {
            assertEquals(concurrency, timesAcquired.get(key).longValue());
        }
        // assert there are no mutexes leftover
        assertEquals(0, contextMutexFactory.mutexMap.size());

        if (testFailed.get()) {
            fail("Failure due to exception while waiting on cyclic barrier.");
        }
    }