Java 21 virtual threads and Guava striped locks replacement

75 views Asked by At

Striped locks, as popularized with Google Guava java library, allow the user to trade between required concurrency and memory footprint. However, I wonder if this is still true with Java 21 virtual threads? Also, are there are alternatives to Guava Striped<L> class (preferably java code depending on Java alone)? I do not want to add dependency to Guava just for this.

UPDATE: I am considering Guava "striped locks" replacement code like this - any opinions?

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class StripedLocks {

    private final int stripes;
    private final transient ReferenceQueue<LockHolder> queue;
    private final transient ConcurrentHashMap<Integer, WeakReference<LockHolder>> locks;

    public StripedLocks(int stripes) {
        this.stripes = stripes;
        queue = new ReferenceQueue<>();
        locks = new ConcurrentHashMap<>();
    }

    public StripedLocks() {
        this(4);
    }

    public final <T> T read(Object keyObject, Callable<T> readOperation) throws Exception {
        return execute(getLock(keyObject).readLock(), readOperation);
    }

    public final <T> T write(Object keyObject, Callable<T> writeOperation) throws Exception {
        return execute(getLock(keyObject).writeLock(), writeOperation);
    }

    private ReentrantReadWriteLock getLock(Object keyObject) {
        Objects.requireNonNull(keyObject,"keyObject can't be null");
        var key = keyObject.hashCode() % stripes;
        return locks.compute(key, (_, currentReference) -> {
            if(currentReference==null)
                return new WeakReference<>(new LockHolder(key, new ReentrantReadWriteLock()), queue);
            var lockHolder = currentReference.get();
            if (lockHolder == null)
                return new WeakReference<>(new LockHolder(key, new ReentrantReadWriteLock()), queue);
            return currentReference;
        }).get().lock();
    }

    private <T> T execute(Lock theLock, Callable<T> operation) throws Exception {
        theLock.lock();
        try {
            return operation.call();
        } finally {
            theLock.unlock();
            purgeStaleLocks();
        }
    }

    @SuppressWarnings("unchecked")
    void purgeStaleLocks() {
        Reference<LockHolder> reference;
        while ((reference = (Reference<LockHolder>) queue.poll()) != null) {
            synchronized (queue) {
                locks.remove(reference.get().key());
            }
        }
    }

    private record LockHolder(int key, ReentrantReadWriteLock lock) {}

}
0

There are 0 answers