[jboss-cvs] JBossCache/src/org/jboss/cache/lock ...
Manik Surtani
manik at jboss.org
Tue Jun 19 06:45:43 EDT 2007
User: msurtani
Date: 07/06/19 06:45:43
Added: src/org/jboss/cache/lock StripedLock.java
Log:
CL thread safety
Revision Changes Path
1.1 date: 2007/06/19 10:45:43; author: msurtani; state: Exp;JBossCache/src/org/jboss/cache/lock/StripedLock.java
Index: StripedLock.java
===================================================================
package org.jboss.cache.lock;
import net.jcip.annotations.ThreadSafe;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.Fqn;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* A simple implementation of lock striping, using Fqns as the keys to lock on, primarily used to help make
* {@link org.jboss.cache.loader.CacheLoader} implemtations thread safe.
* <p/>
* Backed by a set of {@link java.util.concurrent.locks.ReentrantReadWriteLock} instances, and using the {@link org.jboss.cache.Fqn}
* hashcodes to determine buckets.
* <p/>
* Since buckets are used, it doesn't matter that the Fqn in question is not removed from the lock map when no longer in
* use, since the Fqn is not referenced in this class. Rather, the hash code is used.
* <p/>
*
* @author <a href="mailto:manik at jboss.org">Manik Surtani</a>
* @since 2.0.0
*/
@ThreadSafe
public class StripedLock
{
private static final int DEFAULT_CONCURRENCY = 20;
private int lockSegmentMask;
private int lockSegmentShift;
private ReentrantReadWriteLock[] sharedLocks;
private Log log = LogFactory.getLog(StripedLock.class);
/**
* This constructor just calls {@link #StripedLock(int)} with a default concurrency value of 20.
*/
public StripedLock()
{
this(DEFAULT_CONCURRENCY);
}
/**
* Creates a new StripedLock which uses a certain number of shared locks across all elements that need to be locked.
*
* @param concurrency number of threads expected to use this class concurrently.
*/
public StripedLock(int concurrency)
{
int tempLockSegShift = 0;
int numLocks = 1;
while (numLocks < concurrency)
{
++tempLockSegShift;
numLocks <<= 1;
}
lockSegmentShift = 32 - tempLockSegShift;
lockSegmentMask = numLocks - 1;
sharedLocks = new ReentrantReadWriteLock[numLocks];
for (int i = 0; i < numLocks; i++) sharedLocks[i] = new ReentrantReadWriteLock();
}
/**
* Blocks until a lock is acquired.
*
* @param fqn the Fqn to lock on
* @param writeLock if true, a write (exclusive) lock is attempted, otherwise a read (shared) lock is used.
*/
public void acquireLock(Fqn fqn, boolean writeLock)
{
ReentrantReadWriteLock lock = getLock(fqn);
// log.error("I want a " + (writeLock ? "WL" : "RL") + " and lock ownership is " + lock.toString());
if (writeLock)
lock.writeLock().lock();
else
lock.readLock().lock();
}
/**
* Releases a lock the caller may be holding.
*
* @param fqn the Fqn to release
*/
public void releaseLock(Fqn fqn)
{
ReentrantReadWriteLock lock = getLock(fqn);
// log.error("I want to release the lock. Status " + lock);
try
{
lock.readLock().unlock();
}
catch (IllegalMonitorStateException imsa)
{
log.trace("Caught exception attempting to release a read lock. Perhaps we have a write lock?");
lock.writeLock().unlock();
}
}
protected ReentrantReadWriteLock getLock(Object o)
{
return sharedLocks[hashToIndex(o)];
}
protected int hashToIndex(Object o)
{
return (hash(o) >>> lockSegmentShift) & lockSegmentMask;
}
/**
* Returns a hash code for non-null Object x.
* Uses the same hash code spreader as most other java.util hash tables.
*
* @param x the object serving as a key
* @return the hash code
*/
private int hash(Object x)
{
int h = x.hashCode();
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
}
}
More information about the jboss-cvs-commits
mailing list