io.funtom.util.concurrent.PerKeyReadWriteSynchronizedExecutor Maven / Gradle / Ivy
Show all versions of java-utils Show documentation
package io.funtom.util.concurrent;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.function.Supplier;
/**
* An Executor which executes tasks on the caller thread.
* The tasks will be executed synchronously on a per-key basis.
* By saying per-key, we mean that thread safety is guaranteed for threads calling it with equals keys.
* For different threads calling the executor with equals keys,
*
* Calls to readExecute(...) methods:
*
- Never lock each other
* - Have the same memory semantics as locking and unlocking the read lock of a java.util.concurrent.lock.{@link ReadWriteLock}
*
* Calls to writeExecute(...) methods:
*
- Never overlaps with any other calls to execute methods
* - Have the same memory semantics as locking and unlocking the write lock of a java.util.concurrent.lock.{@link ReadWriteLock}
*
* On the other hand, the executor is implemented so calls from different threads, with keys that are not equals, will be executed concurrently with minimal contention between the calls.
* Calling threads might be suspended.
*/
public final class PerKeyReadWriteSynchronizedExecutor {
private static final int CONCURRENCY_LEVEL = 32;
private final ConcurrencySegment[] concurrencySegments;
@SuppressWarnings({"unchecked"})
public PerKeyReadWriteSynchronizedExecutor() {
concurrencySegments = (ConcurrencySegment[]) new ConcurrencySegment[CONCURRENCY_LEVEL];
for (int i = 0; i < CONCURRENCY_LEVEL; i++) {
concurrencySegments[i] = new ConcurrencySegment<>(ReadWriteSynchronizedExecutor::new);
}
}
public void readExecute(KEY_TYPE key, Runnable task) {
ConcurrencySegment s = getSegment(key);
ReadWriteSynchronizedExecutor executor = s.getValue(key);
try {
executor.readExecute(task);
} finally {
s.releaseKey(key);
}
}
public R readExecute(KEY_TYPE key, Supplier task) throws Exception {
ConcurrencySegment s = getSegment(key);
ReadWriteSynchronizedExecutor executor = s.getValue(key);
try {
return executor.readExecute(task);
} finally {
s.releaseKey(key);
}
}
public void writeExecute(KEY_TYPE key, Runnable task) {
ConcurrencySegment s = getSegment(key);
ReadWriteSynchronizedExecutor executor = s.getValue(key);
try {
executor.writeExecute(task);
} finally {
s.releaseKey(key);
}
}
public R writeExecute(KEY_TYPE key, Supplier task) {
ConcurrencySegment s = getSegment(key);
ReadWriteSynchronizedExecutor executor = s.getValue(key);
try {
return executor.writeExecute(task);
} finally {
s.releaseKey(key);
}
}
private ConcurrencySegment getSegment(KEY_TYPE key) {
int segmentIndex = HashUtil.boundedHash(key, CONCURRENCY_LEVEL);
return concurrencySegments[segmentIndex];
}
}