All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.lettuce.core.protocol.SharedLock Maven / Gradle / Ivy

Go to download

Advanced and thread-safe Java Redis client for synchronous, asynchronous, and reactive usage. Supports Cluster, Sentinel, Pipelining, Auto-Reconnect, Codecs and much more.

The newest version!
package io.lettuce.core.protocol;

import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;

import io.lettuce.core.internal.LettuceAssert;

/**
 * Shared locking facade that supports shared and exclusive locking.
 * 

* Multiple shared locks (writers) are allowed concurrently to process their work. If an exclusive lock is requested, the * exclusive lock requestor will wait until all shared locks are released and the exclusive worker is permitted. *

* Exclusive locking is reentrant. An exclusive lock owner is permitted to acquire and release shared locks. Shared/exclusive * lock requests by other threads than the thread which holds the exclusive lock, are forced to wait until the exclusive lock is * released. * * @author Mark Paluch */ class SharedLock { private static final AtomicLongFieldUpdater WRITERS = AtomicLongFieldUpdater.newUpdater(SharedLock.class, "writers"); private final Lock lock = new ReentrantLock(); private final ThreadLocal threadWriters = ThreadLocal.withInitial(() -> 0); private volatile long writers = 0; private volatile Thread exclusiveLockOwner; /** * Wait for stateLock and increment writers. Will wait if stateLock is locked and if writer counter is negative. */ void incrementWriters() { if (exclusiveLockOwner == Thread.currentThread()) { return; } lock.lock(); try { for (;;) { if (WRITERS.get(this) >= 0) { WRITERS.incrementAndGet(this); threadWriters.set(threadWriters.get() + 1); return; } } } finally { lock.unlock(); } } /** * Decrement writers without any wait. */ void decrementWriters() { if (exclusiveLockOwner == Thread.currentThread()) { return; } WRITERS.decrementAndGet(this); threadWriters.set(threadWriters.get() - 1); } /** * Execute a {@link Runnable} guarded by an exclusive lock. * * @param runnable the runnable, must not be {@code null}. */ void doExclusive(Runnable runnable) { LettuceAssert.notNull(runnable, "Runnable must not be null"); doExclusive(() -> { runnable.run(); return null; }); } /** * Retrieve a value produced by a {@link Supplier} guarded by an exclusive lock. * * @param supplier the {@link Supplier}, must not be {@code null}. * @param the return type * @return the return value */ T doExclusive(Supplier supplier) { LettuceAssert.notNull(supplier, "Supplier must not be null"); lock.lock(); try { try { lockWritersExclusive(); return supplier.get(); } finally { unlockWritersExclusive(); } } finally { lock.unlock(); } } /** * Wait for stateLock and no writers. Must be used in an outer {@code synchronized} block to prevent interleaving with other * methods using writers. Sets writers to a negative value to create a lock for {@link #incrementWriters()}. */ private void lockWritersExclusive() { if (exclusiveLockOwner == Thread.currentThread()) { WRITERS.decrementAndGet(this); return; } lock.lock(); try { for (;;) { // allow reentrant exclusive lock by comparing writers count and threadWriters count if (WRITERS.compareAndSet(this, threadWriters.get(), -1)) { exclusiveLockOwner = Thread.currentThread(); return; } } } finally { lock.unlock(); } } /** * Unlock writers. */ private void unlockWritersExclusive() { if (exclusiveLockOwner == Thread.currentThread()) { // check exclusive look not reentrant first if (WRITERS.compareAndSet(this, -1, threadWriters.get())) { exclusiveLockOwner = null; return; } // otherwise unlock until no more reentrant left WRITERS.incrementAndGet(this); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy