public static ByteBufferIndexInput newInstance(
     String resourceDescription,
     ByteBuffer[] buffers,
     long length,
     int chunkSizePower,
     BufferCleaner cleaner,
     boolean trackClones) {
   final WeakIdentityMap<ByteBufferIndexInput, Boolean> clones =
       trackClones ? WeakIdentityMap.<ByteBufferIndexInput, Boolean>newConcurrentHashMap() : null;
   if (buffers.length == 1) {
     return new SingleBufferImpl(
         resourceDescription, buffers[0], length, chunkSizePower, cleaner, clones);
   } else {
     return new DefaultImpl(resourceDescription, buffers, length, chunkSizePower, cleaner, clones);
   }
 }
  public void testConcurrentHashMap() throws Exception {
    // don't make threadCount and keyCount random, otherwise easily OOMs or fails otherwise:
    final int threadCount = 8, keyCount = 1024;
    final ExecutorService exec =
        Executors.newFixedThreadPool(threadCount, new NamedThreadFactory("testConcurrentHashMap"));
    final WeakIdentityMap<Object, Integer> map =
        WeakIdentityMap.newConcurrentHashMap(random().nextBoolean());
    // we keep strong references to the keys,
    // so WeakIdentityMap will not forget about them:
    final AtomicReferenceArray<Object> keys = new AtomicReferenceArray<Object>(keyCount);
    for (int j = 0; j < keyCount; j++) {
      keys.set(j, new Object());
    }

    try {
      for (int t = 0; t < threadCount; t++) {
        final Random rnd = new Random(random().nextLong());
        exec.execute(
            new Runnable() {
              @Override
              public void run() {
                final int count = atLeast(rnd, 10000);
                for (int i = 0; i < count; i++) {
                  final int j = rnd.nextInt(keyCount);
                  switch (rnd.nextInt(5)) {
                    case 0:
                      map.put(keys.get(j), Integer.valueOf(j));
                      break;
                    case 1:
                      final Integer v = map.get(keys.get(j));
                      if (v != null) {
                        assertEquals(j, v.intValue());
                      }
                      break;
                    case 2:
                      map.remove(keys.get(j));
                      break;
                    case 3:
                      // renew key, the old one will be GCed at some time:
                      keys.set(j, new Object());
                      break;
                    case 4:
                      // check iterator still working
                      for (Iterator<Object> it = map.keyIterator(); it.hasNext(); ) {
                        assertNotNull(it.next());
                      }
                      break;
                    default:
                      fail("Should not get here.");
                  }
                }
              }
            });
      }
    } finally {
      exec.shutdown();
      while (!exec.awaitTermination(1000L, TimeUnit.MILLISECONDS)) ;
    }

    // clear strong refs
    for (int j = 0; j < keyCount; j++) {
      keys.set(j, null);
    }

    // check that GC does not cause problems in reap() method:
    int size = map.size();
    for (int i = 0; size > 0 && i < 10; i++)
      try {
        System.runFinalization();
        System.gc();
        int newSize = map.size();
        assertTrue("previousSize(" + size + ")>=newSize(" + newSize + ")", size >= newSize);
        size = newSize;
        Thread.sleep(100L);
        int c = 0;
        for (Iterator<Object> it = map.keyIterator(); it.hasNext(); ) {
          assertNotNull(it.next());
          c++;
        }
        newSize = map.size();
        assertTrue("previousSize(" + size + ")>=iteratorSize(" + c + ")", size >= c);
        assertTrue("iteratorSize(" + c + ")>=newSize(" + newSize + ")", c >= newSize);
        size = newSize;
      } catch (InterruptedException ie) {
      }
  }