io.funtom.util.concurrent.PerKeySynchronizedExecutor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-utils Show documentation
Show all versions of java-utils Show documentation
A Java utils library, contains common utils
package io.funtom.util.concurrent;
import java.util.concurrent.locks.Lock;
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.
* When two threads calling the executor with equals keys, the executions will never overlap each other.
* 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.
* Calling execute from different thread with equals keys has the same memory semantics as locking and releasing a java.util.concurrent.locks.{@link Lock}.
*/
public final class PerKeySynchronizedExecutor {
private static final int CONCURRENCY_LEVEL = 32;
private final ConcurrencySegment[] segments;
@SuppressWarnings({"unchecked"})
public PerKeySynchronizedExecutor() {
segments = (ConcurrencySegment[]) new ConcurrencySegment[CONCURRENCY_LEVEL];
for (int i = 0; i < CONCURRENCY_LEVEL; i++) {
segments[i] = new ConcurrencySegment<>(SynchronizedExecutor::new);
}
}
public void execute(KEY_TYPE key, Runnable task) {
int segmentIndex = HashUtil.boundedHash(key, CONCURRENCY_LEVEL);
ConcurrencySegment s = segments[segmentIndex];
SynchronizedExecutor executor = s.getValue(key);
try {
executor.execute(task);
} finally {
s.releaseKey(key);
}
}
public R execute(KEY_TYPE key, Supplier task) {
int segmentIndex = HashUtil.boundedHash(key, CONCURRENCY_LEVEL);
ConcurrencySegment s = segments[segmentIndex];
SynchronizedExecutor executor = s.getValue(key);
try {
return executor.execute(task);
} finally {
s.releaseKey(key);
}
}
}