public class ReentrantDistributedZookeeperLock extends Object implements DistributedLock
ReentrantLock, except that it uses Zookeeper to
share the lock state across multiple nodes, allowing for a distributed lock. The owning thread may acquire the lock multiple times, but must unlock for each time the lock is
acquired. It's important to get in the habit of unlocking immediately in a finally block to prevent orphaned locks:
Lock lock = new ReentrantDistributedZookeeperLock(zk, "/solr-update/locks", "solrUpdate_commandLock");
lock.lockInterruptibly(); //This will block until a lock is acquired or until the Thread is interrupted.
try {
//Do something in a globally locked state
} finally {
lock.unlock();
}
or
Lock lock = new ReentrantDistributedZookeeperLock(zk, "/solr-update/locks", "solrUpdate_commandLock");
if (lock.tryLock()) {
try {
//Do something in a globally locked state
} finally {
lock.unlock();
}
}
In terms of performance, the average lock time, on a single quad-core laptop running a single Zookeeper instance, takes about 7-8 milliseconds.
And the average unlock time also takes around 7-8 milliseconds during a simple test on a quad core laptop that was also running a single Zookeeper instance.
This is with a single thread, and is assuming no reentrant locks and no contention or waiting for locks to become available.
In other words, disregarding blocking and contention, it will likely take, on average, 14-16 milliseconds to create and release a lock
(approximately 55-65 locks and releases / second for any given lock). These metrics will depend on a number of things, including contention for locks,
Zookeeper cluster size and configuration, hardware, etc.
DistributedLock.DistributedLockException| Modifier and Type | Field and Description |
|---|---|
static String |
DEFAULT_BASE_FOLDER
This is the base folder that all locks will be written to in Zookeeper.
|
static String |
LOCK_PREFIX
This is the prefix of any lock entry.
|
GLOBAL_ENV_CAN_OBTAIN_LOCK_PROPERTY_NAME| Constructor and Description |
|---|
ReentrantDistributedZookeeperLock(org.apache.zookeeper.ZooKeeper zk,
String lockPath,
String lockName) |
ReentrantDistributedZookeeperLock(org.apache.zookeeper.ZooKeeper zk,
String lockPath,
String lockName,
boolean useDefaultBasePath,
List<org.apache.zookeeper.data.ACL> acls)
This constructor takes in the
ZooKeeper (non-nullable),
the lock path (non-nullable and in the format of '/path/to/this/lock/folder`),
and the lock name (non-nullable and non-empty string with no whitespaces, leading or trailing slashes, or special characters except '-' or '_'). |
ReentrantDistributedZookeeperLock(org.apache.zookeeper.ZooKeeper zk,
String lockPath,
String lockName,
org.springframework.core.env.Environment env,
boolean useDefaultBasePath,
List<org.apache.zookeeper.data.ACL> acls)
This constructor takes in the
ZooKeeper (non-nullable),
the lock path (non-nullable and in the format of '/path/to/this/lock/folder`),
the lock name (non-nullable and non-empty string with no whitespaces, leading or trailing slashes, or special characters except '-' or '_'), and
an Environment object, which can be null. |
ReentrantDistributedZookeeperLock(org.apache.zookeeper.ZooKeeper zk,
String lockPath,
String lockName,
org.springframework.core.env.Environment env,
List<org.apache.zookeeper.data.ACL> acls)
This constructor takes in the
Zookeeper (non-nullable),
the lock path (non-nullable and in the format of '/path/to/this/lock/folder`),
the lock name (non-nullable and non-empty string with no whitespaces, leading or trailing slashes, or special characters except '-' or '_'), and
an Environment object, which can be null. |
ReentrantDistributedZookeeperLock(org.apache.zookeeper.ZooKeeper zk,
String lockPath,
String lockName,
List<org.apache.zookeeper.data.ACL> acls)
This constructor takes in the
ZooKeeper (non-nullable),
the lock path (non-nullable and in the format of '/path/to/this/lock/folder`),
and the lock name (non-nullable and non-empty string with no whitespaces, leading or trailing slashes, or special characters except '-' or '_'). |
| Modifier and Type | Method and Description |
|---|---|
boolean |
canParticipate()
Allows one to disable this locking mechanism via the 'org.broadleafcommerce.core.util.lock.DistributedLock.canParticipate' (globally) or the
'org.broadleafcommerce.core.util.lock.DistributedLock.${lockName}.canParticipate' property.
|
boolean |
currentThreadHoldsLock()
Indicates if the current thread holds the lock.
|
protected List<org.apache.zookeeper.data.ACL> |
getAcls()
Returns a list of Zookeeper ACLs to be used for this lock.
|
int |
getCurrentThreadLockPermits() |
protected org.springframework.core.env.Environment |
getEnvironment() |
protected int |
getFailureRetries()
This will retry any interactions with Zookeeper this many times.
|
protected String |
getFullLockName()
Returns LOCK_PREFIX + getLockName()
E.g.
|
protected String |
getLockAccessPropertyName() |
protected String |
getLockFolderPath() |
protected String |
getLockName()
The lock name provided in the constructor.
|
protected long |
getRetryWaitTime()
If an interaction with Zookeeper fails, it will retry and this will be the pause time, in millis, between retries.
|
protected org.apache.zookeeper.ZooKeeper |
getZookeeperClient() |
protected void |
initialize()
Creates the appropriate folder(s) in Zookeeper if they don't already exist.
|
protected boolean |
isAdditiveWaitTtimes()
If this is true, the wait time in millis will be incremented by itself each time a retry occurs, up to the retry count.
|
void |
lock() |
protected boolean |
lockInternally(long waitTime)
Negative number means wait indefinitely (typically until an
UnsupportedOperationException is thrown. |
void |
lockInterruptibly() |
Condition |
newCondition() |
boolean |
tryLock() |
boolean |
tryLock(long time,
TimeUnit unit) |
void |
unlock() |
public static final String DEFAULT_BASE_FOLDER
public static final String LOCK_PREFIX
public ReentrantDistributedZookeeperLock(org.apache.zookeeper.ZooKeeper zk,
String lockPath,
String lockName)
public ReentrantDistributedZookeeperLock(org.apache.zookeeper.ZooKeeper zk,
String lockPath,
String lockName,
List<org.apache.zookeeper.data.ACL> acls)
ZooKeeper (non-nullable),
the lock path (non-nullable and in the format of '/path/to/this/lock/folder`),
and the lock name (non-nullable and non-empty string with no whitespaces, leading or trailing slashes, or special characters except '-' or '_').
This Lock will, by default, participate in or be allowed to acquire a lock.
The lockPath will be prepended with '/broadleaf/app/distributed-locks'.zk - lockPath - lockName - acls - public ReentrantDistributedZookeeperLock(org.apache.zookeeper.ZooKeeper zk,
String lockPath,
String lockName,
boolean useDefaultBasePath,
List<org.apache.zookeeper.data.ACL> acls)
ZooKeeper (non-nullable),
the lock path (non-nullable and in the format of '/path/to/this/lock/folder`),
and the lock name (non-nullable and non-empty string with no whitespaces, leading or trailing slashes, or special characters except '-' or '_').
This Lock will, by default, participate in or be allowed to acquire a lock.
If use defaultBasePath is true, then the lockPath will be prepended with '/broadleaf/app/distributed-locks'.zk - lockPath - lockName - acls - public ReentrantDistributedZookeeperLock(org.apache.zookeeper.ZooKeeper zk,
String lockPath,
String lockName,
org.springframework.core.env.Environment env,
List<org.apache.zookeeper.data.ACL> acls)
Zookeeper (non-nullable),
the lock path (non-nullable and in the format of '/path/to/this/lock/folder`),
the lock name (non-nullable and non-empty string with no whitespaces, leading or trailing slashes, or special characters except '-' or '_'), and
an Environment object, which can be null.
This Lock will, by default, participate in or be allowed to acquire a lock if the Environment argument is null or
if the 'org.broadleafcommerce.core.util.lock.DistributedLock.${lockName}.canParticipate' property is not set or is set to false.
The lockPath will be prepended with '/broadleaf/app/distributed-locks'.zk - lockPath - lockName - env - acls - public ReentrantDistributedZookeeperLock(org.apache.zookeeper.ZooKeeper zk,
String lockPath,
String lockName,
org.springframework.core.env.Environment env,
boolean useDefaultBasePath,
List<org.apache.zookeeper.data.ACL> acls)
ZooKeeper (non-nullable),
the lock path (non-nullable and in the format of '/path/to/this/lock/folder`),
the lock name (non-nullable and non-empty string with no whitespaces, leading or trailing slashes, or special characters except '-' or '_'), and
an Environment object, which can be null.
This Lock will, by default, participate in or be allowed to acquire a lock if the Environment argument is null or
if the 'org.broadleafcommerce.core.util.lock.DistributedLock.${lockName}.canParticipate' property is not set or is set to false.
If use defaultBasePath is true, then the lockPath will be prepended with '/broadleaf/app/distributed-locks'.zk - lockPath - lockName - env - useDefaultBasePath - acls - public void lockInterruptibly()
throws InterruptedException
lockInterruptibly in interface LockInterruptedExceptionpublic boolean tryLock(long time,
TimeUnit unit)
throws InterruptedException
tryLock in interface LockInterruptedExceptionpublic Condition newCondition()
newCondition in interface Lockprotected boolean lockInternally(long waitTime)
throws InterruptedException
UnsupportedOperationException is thrown.
Zero (0) means don't wait.
Positive number means wait for that number of millis.waitTime - InterruptedExceptionprotected void initialize()
public boolean canParticipate()
Environment is not null, this first checks the more specific
'org.broadleafcommerce.core.util.lock.DistributedLock.${lockName}.canParticipate' property. If that is true or
null, then it checks the more global 'org.broadleafcommerce.core.util.lock.DistributedLock.canParticipate'. If that is true or null then it returns true.
By default, this method returns true if the Environment is null or if both properties are null.
If this method returns false, then the locking mechanisms and semantics will continue to work.
However, the lock will always be locked and will never allow the acquisition of a lock.canParticipate in interface DistributedLockpublic boolean currentThreadHoldsLock()
DistributedLockcurrentThreadHoldsLock in interface DistributedLockpublic int getCurrentThreadLockPermits()
protected org.apache.zookeeper.ZooKeeper getZookeeperClient()
protected org.springframework.core.env.Environment getEnvironment()
protected String getLockName()
protected String getFullLockName()
protected String getLockFolderPath()
protected int getFailureRetries()
protected long getRetryWaitTime()
protected boolean isAdditiveWaitTtimes()
protected String getLockAccessPropertyName()
protected List<org.apache.zookeeper.data.ACL> getAcls()
Copyright © 2026. All rights reserved.