/**
   * Time a multi-threaded access to a cache.
   *
   * @return the timing stopwatch
   */
  private <V> StopWatch timeMultiThreaded(
      String id, final Map<Integer, V> map, ValueFactory<V> factory) throws InterruptedException {

    StopWatch stopWatch = new StopWatch(id);
    for (int i = 0; i < 500; i++) {
      map.put(i, factory.newValue(i));
    }
    Thread[] threads = new Thread[30];
    stopWatch.start("Running threads");
    for (int threadIndex = 0; threadIndex < threads.length; threadIndex++) {
      threads[threadIndex] =
          new Thread("Cache access thread " + threadIndex) {
            @Override
            public void run() {
              for (int j = 0; j < 1000; j++) {
                for (int i = 0; i < 1000; i++) {
                  map.get(i);
                }
              }
            }
          };
    }
    for (Thread thread : threads) {
      thread.start();
    }

    for (Thread thread : threads) {
      if (thread.isAlive()) {
        thread.join(2000);
      }
    }
    stopWatch.stop();
    return stopWatch;
  }
  @Test
  @Ignore("Intended for use during development only")
  public void shouldBeFasterThanSynchronizedMap() throws Exception {
    Map<Integer, WeakReference<String>> synchronizedMap =
        Collections.synchronizedMap(new WeakHashMap<Integer, WeakReference<String>>());
    StopWatch mapTime =
        timeMultiThreaded(
            "SynchronizedMap",
            synchronizedMap,
            new ValueFactory<WeakReference<String>>() {

              @Override
              public WeakReference<String> newValue(int v) {
                return new WeakReference<String>(String.valueOf(v));
              }
            });
    System.out.println(mapTime.prettyPrint());

    this.map.setDisableTestHooks(true);
    StopWatch cacheTime =
        timeMultiThreaded(
            "WeakConcurrentCache",
            this.map,
            new ValueFactory<String>() {

              @Override
              public String newValue(int v) {
                return String.valueOf(v);
              }
            });
    System.out.println(cacheTime.prettyPrint());

    // We should be at least 4 time faster
    assertThat(cacheTime.getTotalTimeSeconds(), is(lessThan(mapTime.getTotalTimeSeconds() / 4.0)));
  }