package com.ctriposs.bigcache.lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* The StripedReadWriteLock is lock holder that contains array of
* {@link java.util.concurrent.locks.ReentrantReadWriteLock}, on which lock/unlock
* operations are performed. Purpose of this is to decrease lock contention.
* When a lock requested, this lock gives a lock associated with the given id.
*/
public class StripedReadWriteLock {
private final ReentrantReadWriteLock[] locks;
/**
* Default factor, creates 16 locks
*/
public StripedReadWriteLock() {
this(4);
}
/**
* Creates array of locks, size of array may be any from set {2^1, 2^2, ..., 2^11}
*
* @param storagePower size of array will be equal to 2^storagePower
*/
public StripedReadWriteLock(int storagePower) {
if (!(storagePower >= 1 && storagePower <= 11)) {
throw new IllegalArgumentException("storage power must be in {1..11}");
}
int lockSize = (int) Math.pow(2, storagePower);
locks = new ReentrantReadWriteLock[lockSize];
for (int i = 0; i < locks.length; i++){
locks[i] = new ReentrantReadWriteLock();
}
}
/**
* Locks lock associated with given id.
*
* @param id value, from which lock is derived
*/
public void readLock(int id) {
getLock(id).readLock().lock();
}
/**
* Unlocks lock associated with given id.
*
* @param id value, from which lock is derived
*/
public void readUnlock(int id) {
getLock(id).readLock().unlock();
}
/**
* Locks lock associated with given id.
*
* @param id value, from which lock is derived
*/
public void writeLock(int id) {
getLock(id).writeLock().lock();
}
/**
* Unlocks lock associated with given id.
*
* @param id value, from which lock is derived
*/
public void writeUnlock(int id) {
getLock(id).writeLock().unlock();
}
/**
* Locks all locks as write lock.
*/
public void writeLockForAll() {
for (int i = 0; i < locks.length; i++) {
getLock(i).writeLock().lock();
}
}
/**
* Unlocks all locks as write lock.
*/
public void writeUnlockForAll() {
for (int i = 0; i < locks.length; i++) {
getLock(i).writeLock().unlock();
}
}
/**
* Finds the lock associated with the id
*
* @param id value, from which lock is derived
* @return lock which is associated with the id
*/
public ReentrantReadWriteLock getLock(int id) {
// locks.length-1 is a string of ones since lock.length is power of 2,
// thus ending cancels out the higher bits of id and leaves the lower bits
// to determine the lock.
return locks[id & (locks.length - 1)];
}
}