Keyed Concurrency Utilities
Advanced concurrency control with keyed utilities
Verifyica provides keyed concurrency utilities for fine-grained synchronization in parallel tests.
Overview
Keyed concurrency utilities allow you to synchronize on specific keys rather than globally:
- KeyedMutexManager - Mutual exclusion per key
- KeyedLatchManager - Count-down latches per key
- KeyedSemaphoreManager - Semaphores per key
KeyedMutexManager
Provides mutual exclusion on a per-key basis.
Basic Usage
import org.verifyica.api.concurrent.KeyedMutexManager;
public class MutexTest {
@Verifyica.ArgumentSupplier(parallelism = 10)
public static Object arguments() {
return List.of("user-1", "user-2", "user-3");
}
@Verifyica.Test
public void testConcurrentAccess(String userId) {
// Only one test can access this user at a time
KeyedMutexManager.lock(userId);
try {
updateUser(userId);
} finally {
KeyedMutexManager.unlock(userId);
}
}
}
Example: Database Row Locking
public class RowLockTest {
@Verifyica.Test
public void testRowUpdate(String rowId) {
KeyedMutexManager.lock(rowId);
try {
// Exclusive access to this row
Row row = database.getRow(rowId);
row.setValue(row.getValue() + 1);
database.updateRow(row);
} finally {
KeyedMutexManager.unlock(rowId);
}
}
}
KeyedLatchManager
Count-down latches per key for coordination.
Basic Usage
import org.verifyica.api.concurrent.KeyedLatchManager;
public class LatchTest {
@Verifyica.BeforeAll
public void beforeAll(String group) {
// Initialize latch for this group (3 tests must complete)
KeyedLatchManager.createLatch(group, 3);
}
@Verifyica.Test
public void test1(String group) throws InterruptedException {
performTest1();
KeyedLatchManager.countDown(group);
// Wait for all 3 tests to complete
KeyedLatchManager.await(group);
// Now all tests have completed
verifyResults(group);
}
}
Example: Barrier Synchronization
public class BarrierTest {
@Verifyica.ArgumentSupplier(parallelism = 5)
public static Object arguments() {
return List.of("batch-1", "batch-2");
}
@Verifyica.BeforeAll
public void beforeAll(String batch) {
// Each batch has 5 tests that must sync
KeyedLatchManager.createLatch(batch, 5);
}
@Verifyica.Test
public void coordinatedTest(String batch) throws InterruptedException {
// Phase 1: Prepare
prepare();
// Signal ready and wait for others
KeyedLatchManager.countDown(batch);
KeyedLatchManager.await(batch);
// Phase 2: All execute together
executeTest();
}
}
KeyedSemaphoreManager
Semaphores per key for resource limiting.
Basic Usage
import org.verifyica.api.concurrent.KeyedSemaphoreManager;
public class SemaphoreTest {
@Verifyica.BeforeAll
public void beforeAll(String resource) {
// Limit to 3 concurrent accesses per resource
KeyedSemaphoreManager.createSemaphore(resource, 3);
}
@Verifyica.Test
public void testLimitedAccess(String resource) throws InterruptedException {
KeyedSemaphoreManager.acquire(resource);
try {
// Max 3 tests can access this resource concurrently
accessResource(resource);
} finally {
KeyedSemaphoreManager.release(resource);
}
}
}
Example: API Rate Limiting
public class RateLimitTest {
@Verifyica.BeforeAll
public void beforeAll(String apiEndpoint) {
// Each endpoint allows 10 concurrent requests
KeyedSemaphoreManager.createSemaphore(apiEndpoint, 10);
}
@Verifyica.Test
public void testApiCall(String apiEndpoint) throws InterruptedException {
KeyedSemaphoreManager.acquire(apiEndpoint);
try {
ApiClient client = new ApiClient();
Response response = client.call(apiEndpoint);
assert response.getStatus() == 200;
} finally {
KeyedSemaphoreManager.release(apiEndpoint);
}
}
}
Combined Example: Multi-Level Coordination
public class ComplexCoordinationTest {
@Verifyica.ArgumentSupplier(parallelism = 20)
public static Object arguments() {
List<Argument<TestData>> args = new ArrayList<>();
for (int i = 0; i < 100; i++) {
String userId = "user-" + (i % 10); // 10 unique users
String pool = "pool-" + (i % 5); // 5 pools
String phase = "phase-1"; // All in same phase
args.add(Argument.of("test-" + i, new TestData(userId, pool, phase)));
}
return args;
}
@Verifyica.BeforeAll
public void beforeAll(TestData data) {
// Limit concurrent access per pool
KeyedSemaphoreManager.createSemaphore(data.getPool(), 5);
// Initialize phase gate for coordination
KeyedLatchManager.createLatch(data.getPhase(), 100);
}
@Verifyica.Test
public void complexTest(TestData data) throws InterruptedException {
// 1. Acquire pool permit (max 5 per pool)
KeyedSemaphoreManager.acquire(data.getPool());
try {
// 2. Lock specific user (exclusive access)
KeyedMutexManager.lock(data.getUserId());
try {
performUserOperation(data.getUserId());
} finally {
KeyedMutexManager.unlock(data.getUserId());
}
// 3. Signal phase completion
KeyedLatchManager.countDown(data.getPhase());
// 4. Wait for all to complete phase
KeyedLatchManager.await(data.getPhase());
// 5. All proceed together
performCoordinatedOperation(data);
} finally {
KeyedSemaphoreManager.release(data.getPool());
}
}
}
Best Practices
Always Use Try-Finally
// Good: Always unlock/release in finally
KeyedMutexManager.lock(key);
try {
// Critical section
} finally {
KeyedMutexManager.unlock(key);
}
// Bad: Might not unlock on exception
KeyedMutexManager.lock(key);
// Critical section
KeyedMutexManager.unlock(key); // Might not execute!
Clean Up Resources
@Verifyica.Conclude
public void conclude(ClassContext classContext) {
// Note: KeyedMutexManager, KeyedLatchManager, and KeyedSemaphoreManager
// automatically clean up keys when they are no longer in use.
// Manual cleanup is typically not required.
}
Avoid Deadlocks
// Bad: Can cause deadlock
KeyedMutexManager.lock(key1);
KeyedMutexManager.lock(key2); // Another thread might lock in reverse order
// Good: Lock in consistent order
List<String> keys = List.of(key1, key2);
Collections.sort(keys);
for (String key : keys) {
KeyedMutexManager.lock(key);
}
try {
// Critical section
} finally {
for (String key : keys) {
KeyedMutexManager.unlock(key);
}
}
Set Appropriate Timeouts
// Good: Use timeouts to avoid infinite waits
if (!KeyedLatchManager.await(key, 30, TimeUnit.SECONDS)) {
throw new TimeoutException("Coordination timed out");
}
See Also
- Parallelism - Advanced parallelism patterns
- API Reference → Concurrency - Complete API documentation
- Execution Model - How tests execute
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.