# 4. `@ConcurrencyLimit`: BLOCK, REJECT, and nesting with retry [← 3. @Retryable measured](03-retryable-measured.md) · [Index](../README.md) · Next: [5. Retry and transactions →](05-retry-and-transactions.md) Ten virtual threads call a 200 ms method limited to 2 ([`ReportService`](../src/main/java/com/ankurm/resilience/limit/ReportService.java)): | Setup | Succeeded | Failed | Max inside | Elapsed | Transcript | |---|---|---|---|---|---| | no limit | 10 | - | 10 | 203 ms | [`limit-none.txt`](output/limit-none.txt) | | `@ConcurrencyLimit(2)` (BLOCK) | 10 | - | 2 | 1006 ms | [`limit-block.txt`](output/limit-block.txt) | | `policy = REJECT` | 2 | 8 × `InvocationRejectedException` | 2 | 205 ms | [`limit-reject.txt`](output/limit-reject.txt) | | Resilience4j `@Bulkhead`, `max-wait-duration: 0` | 2 | 8 × `BulkheadFullException` | 2 | 231 ms | [`limit-r4j-bulkhead.txt`](output/limit-r4j-bulkhead.txt) | BLOCK queues callers indefinitely - there is no wait timeout. With virtual threads that is cheap in memory, but an unbounded queue in front of a slow dependency is still an unbounded latency. `InvocationRejectedException` extends `RejectedExecutionException`, so existing handlers for executor rejection catch it. ## Both annotations on one method `limitedAndRetried()` has `@ConcurrencyLimit(1)` and `@Retryable(maxRetries=1, delay=300)`; every caller's first attempt fails. Two callers took **815 ms** ([`limit-limit-and-retry.txt`](output/limit-limit-and-retry.txt)): about 2 × (50 + 300 + 50). The permit is held through the 300 ms back-off, because the limit is the outer interceptor ([`proxy-reports.txt`](output/proxy-reports.txt)): ``` "org.springframework.resilience.annotation.ConcurrencyLimitBeanPostProcessor$ConcurrencyLimitInterceptor order=2147483647", "org.springframework.resilience.annotation.RetryAnnotationBeanPostProcessor$RetryAnnotationInterceptor order=2147483647" ``` Both post-processors insert at the front of an existing proxy, so whichever runs second ends up outermost. If you want the permit released between attempts, put the two annotations on different beans.