### Question:
ValueFilterCounter extends AbstractValueFilter { @Override public ValueObject filterValue(ValueObject value) { if (format != null && dc == null) { dc = new DecimalFormat(format); } int ret = counter.getAndAdd(increment); if (sample > 0) { if (ret % sample != 0) { return null; } if (format == null) { return value; } } if (dc != null) { return ValueFactory.create(dc.format(ret)); } else { return ValueFactory.create(ret); } } @JsonCreator  ValueFilterCounter(@JsonProperty("format") String format,
                              @JsonProperty("start") int start,
                              @JsonProperty("increment") int increment,
                              @JsonProperty("sample") int sample); @Override ValueObject filterValue(ValueObject value);  }### Answer:
@Test public void singleThreadedCounter() { ValueFilterCounter counter = new ValueFilterCounter(null, 0, 1, 0); Thread thread = new CounterThread(counter, 1000000); thread.start(); try { thread.join(); } catch (InterruptedException e) { assertTrue(false); } Long expected = 1000000l; Long observed = counter.filterValue(null).asLong().getLong(); assertEquals(expected, observed); }
@Test public void multiThreadedCounter() { ValueFilterCounter counter = new ValueFilterCounter(null, 0, 1, 0); Thread thread1 = new CounterThread(counter, 1000000); Thread thread2 = new CounterThread(counter, 1000000); Thread thread3 = new CounterThread(counter, 1000000); Thread thread4 = new CounterThread(counter, 1000000); thread1.start(); thread2.start(); thread3.start(); thread4.start(); try { thread1.join(); thread2.join(); thread3.join(); thread4.join(); } catch (InterruptedException e) { assertTrue(false); } Long expected = 4000000l; Long observed = counter.filterValue(null).asLong().getLong(); assertEquals(expected, observed); }