public Optional<Snapshot> getSnapshotAndReset() {
    if (!dirty.getAndSet(false)) {
      return Optional.empty();
    }

    ImmutableLongArray.Builder bucketsSnapshotBuilder =
        ImmutableLongArray.builder(buckets.length());
    for (int i = 0; i < buckets.length(); i++) {
      bucketsSnapshotBuilder.add(buckets.getAndSet(i, 0));
    }
    OutlierStatistic overflowSnapshot = overflowStatistic.getAndSet(OutlierStatistic.EMPTY);
    OutlierStatistic underflowSnapshot = underflowStatistic.getAndSet(OutlierStatistic.EMPTY);

    return Optional.of(
        Snapshot.create(
            underflowSnapshot, overflowSnapshot, bucketsSnapshotBuilder.build(), bucketType));
  }
@Test
  public void testUpdateAndSnapshots_MultipleThreads() {
    int numRunnables = 200;
    ExecutorService executor = Executors.newFixedThreadPool(numRunnables);

    HistogramData.BucketType bucketType = HistogramData.ExponentialBuckets.of(1, 10);
    LockFreeHistogram histogram =
        new LockFreeHistogram(MetricName.named("name", "namespace"), bucketType);

    List<UpdateHistogramCallable> callables = new ArrayList<>();

    for (int i = 0; i < numRunnables; i++) {
      callables.add(new UpdateHistogramCallable(histogram, i));
    }

    long totalValuesRecorded = 0;

    try {
      List<Future<Long>> futures = executor.invokeAll(callables);
      for (Future<Long> future : futures) {
        totalValuesRecorded += future.get();
      }
    } catch (Exception e) {
      return;
    }

    Optional<LockFreeHistogram.Snapshot> finalSnapshot = histogram.getSnapshotAndReset();
    if (finalSnapshot.isPresent()) {
      totalValuesRecorded += finalSnapshot.get().totalCount();
    }

    assertThat(
        totalValuesRecorded, equalTo(numRunnables * UpdateHistogramCallable.numValuesRecorded()));
  }