@Test @InSequence(3) public void callCountedMethodOnce() throws InterruptedException, TimeoutException { assertThat("Counter is not registered correctly", registry.getCounters(), hasKey(COUNTER_NAME)); Counter counter = registry.getCounters().get(COUNTER_NAME); final Exchanger<Long> exchanger = new Exchanger<>(); Thread thread = new Thread(new Runnable() { @Override public void run() { try { exchanger.exchange(bean.monotonicCountedMethod(new Callable<Long>() { @Override public Long call() throws Exception { exchanger.exchange(0L); return exchanger.exchange(0L); } })); } catch (InterruptedException cause) { throw new RuntimeException(cause); } } }); final AtomicInteger uncaught = new AtomicInteger(); thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { uncaught.incrementAndGet(); } }); thread.start(); exchanger.exchange(0L, 5L, TimeUnit.SECONDS); assertThat("Counter count is incorrect", counter.getCount(), is(equalTo(COUNTER_COUNT.incrementAndGet()))); Long random = 1 + Math.round(Math.random() * (Long.MAX_VALUE - 1)); exchanger.exchange(random, 5L, TimeUnit.SECONDS); assertThat("Counted method return value is incorrect", exchanger.exchange(0L), is(equalTo(random))); assertThat("Counter count is incorrect", counter.getCount(), is(equalTo(COUNTER_COUNT.get()))); thread.join(); assertThat("Exception thrown in method call thread", uncaught.get(), is(equalTo(0))); }
@Counted(name = "monotonicCountedMethod", absolute = true, monotonic = true) public T monotonicCountedMethod(Callable<T> callable) { try { return callable.call(); } catch (Exception cause) { throw new RuntimeException(cause); } }
MonotonicCountedMethodBean { @Counted(name = "monotonicCountedMethod", absolute = true, monotonic = true) public T monotonicCountedMethod(Callable<T> callable) { try { return callable.call(); } catch (Exception cause) { throw new RuntimeException(cause); } } }
MonotonicCountedMethodBean { @Counted(name = "monotonicCountedMethod", absolute = true, monotonic = true) public T monotonicCountedMethod(Callable<T> callable) { try { return callable.call(); } catch (Exception cause) { throw new RuntimeException(cause); } }  }
MonotonicCountedMethodBean { @Counted(name = "monotonicCountedMethod", absolute = true, monotonic = true) public T monotonicCountedMethod(Callable<T> callable) { try { return callable.call(); } catch (Exception cause) { throw new RuntimeException(cause); } }  @Counted(name = "monotonicCountedMethod", absolute = true, monotonic = true) T monotonicCountedMethod(Callable<T> callable); }
MonotonicCountedMethodBean { @Counted(name = "monotonicCountedMethod", absolute = true, monotonic = true) public T monotonicCountedMethod(Callable<T> callable) { try { return callable.call(); } catch (Exception cause) { throw new RuntimeException(cause); } }  @Counted(name = "monotonicCountedMethod", absolute = true, monotonic = true) T monotonicCountedMethod(Callable<T> callable);  }