org.springframework.integration.support.locks.DefaultLockRegistry Maven / Gradle / Ivy
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.support.locks;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.springframework.util.Assert;
/**
* Default implementation of {@link LockRegistry} which uses Masked Hashcode algorithm to obtain locks.
* When an instance of this class is created and array of {@link Lock} objects is created. The length of
* the array is based on the 'mask' parameter passed in the constructor. The default mask is 0xFF which will create
* and array consisting of 256 {@link ReentrantLock} instances.
* When the {@link #obtain(Object)} method is called with the lockKey (e.g., Object) the index of the {@link Lock}
* is determined by masking the object's hashCode (e.g., {@code object.hashCode & mask}) and the {@link Lock} is returned.
*
* @author Oleg Zhurakousky
* @author Gary Russell
* @since 2.1.1
*
*/
public final class DefaultLockRegistry implements LockRegistry {
private final Lock[] lockTable;
private final int mask;
/**
* Constructs a DefaultLockRegistry with the default
* mask 0xFF with 256 locks.
*/
public DefaultLockRegistry() {
this(0xFF);
}
/**
* Constructs a DefaultLockRegistry with the supplied
* mask - the mask must have a value Math.pow(2, n) - 1 where n
* is 1 to 31, creating a hash of Math.pow(2, n) locks.
* Examples:
*
* - 0x3ff (1023) - 1024 locks
* - 0xfff (4095) - 4096 locks
*
* @param mask The bit mask.
*/
public DefaultLockRegistry(int mask) {
String bits = Integer.toBinaryString(mask);
Assert.isTrue(bits.length() < 32 && (mask == 0 || bits.lastIndexOf('0') < bits.indexOf('1')), "Mask must be a power of 2 - 1");
this.mask = mask;
int arraySize = this.mask + 1;
this.lockTable = new ReentrantLock[arraySize];
for (int i = 0; i < arraySize; i++) {
this.lockTable[i] = new ReentrantLock();
}
}
/**
* Obtains a lock by masking the lockKey's hashCode() with
* the mask and using the result as an index to the lock table.
* @param lockKey the object used to derive the lock index.
*/
@Override
public Lock obtain(Object lockKey) {
Assert.notNull(lockKey, "'lockKey' must not be null");
Integer lockIndex = lockKey.hashCode() & this.mask;
return this.lockTable[lockIndex];
}
}